跨域请求的解决方案
1 本节任务
理解 ajax 的跨域访问
2Ajax 跨域介绍
跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器
对 JavaScript 施加的安全限制。
什么是同源策略: 所谓的同源,指的是域名、协议、端口均相等。
不同源的系统使用 ajax 发送求,会存在跨域的问题:例如
http://www.abc.com/ 访问 http://www.xyz.com 域名不一致,存在跨域
http://www.abc.com/ 访问 https://www.abc.com 协议不一致,存在跨域
http://www.abc.com:80/ 访问 http://www.abc.com:81 端口不一致,存在跨域
3Ajax 跨域问题
3.1 建立 ajax-origin 项目
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.bjsxt.ajax.origin</groupId> <artifactId>ajax-origin</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <properties> <!-- spring 依赖 --> <spring.version>4.3.18.RELEASE</spring.version> <jstl.version>1.2</jstl.version> <servlet-api.version>2.5</servlet-api.version> <jsp-api.version>2.0</jsp-api.version> <jackson.version>2.9.0</jackson.version> </properties> <dependencies> <!-- jsp 相关依赖 --> <!-- servlet 依赖 --> <!-- jstl 依赖 --> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>${jstl.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>${servlet-api.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> <version>${jsp-api.version}</version> <scope>provided</scope> </dependency> </dependencies> <build> <finalName>ajax</finalName> <plugins> <!-- 配置 Tomcat 插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <path>/ajax</path> <port>9090</port> </configuration> </plugin> </plugins> </build> </project>
3.2 发送 Ajax 请求
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> <script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.js"></script> <script type="text/javascript"> function sendAjax(){ $.post("http://localhost:7070/order/loadOrderList02","uid=1234",function(data){ alert(data); }); } </script> </head> <body><a href="javascript:sendAjax()">sendAjax</a> </body> </html>
3.3 观察跨域问题
4Ajax 跨域解决方案
4.1 服务器段解决
服务端设置 response header 中 Access-Control-Allow-Origin 字段
4.2 前端 JSONP 解决
利用 script 标签,不受同源策略的限制,用户从服务请求数据,服务器返回一个带有方法和数据
的 js 代码。
1 本节任务
服务器段,使用 CORSFilter 过滤器解决跨域问题
2CORSFilter 解决跨域访问原理
通过 CORSFilter 过滤器在服务器端修改 Http 的响应头
Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: http://example.com:8080/
3 修改 order-sys 项目
3.1 添加 CORSFilter 依赖
<dependency> <groupId>com.thetransactioncompany</groupId> <artifactId>cors-filter</artifactId> <version>2.5</version> <scope>runtime</scope>
</dependency>
3.2web.xml 配置 CORSFilter
<filter> <filter-name>CORS</filter-name> <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class> <init-param> <param-name>cors.allowOrigin</param-name> <param-value>*</param-value> </init-param> <init-param> <param-name>cors.supportedMethods</param-name> <param-value>GET, POST, HEAD, PUT, DELETE</param-value> </init-param> <init-param> <param-name>cors.supportedHeaders</param-name> <param-value>Accept, Origin, X-Requested-With, Content-Type, Last-Modified</param-value> </init-param> <init-param> <param-name>cors.exposedHeaders</param-name> <param-value>Set-Cookie</param-value> </init-param> <init-param> <param-name>cors.supportsCredentials</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CORS</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
3.3 启动 order-sys 项目
4 启动 ajax-origin 测试
<!-- fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency>
3.3 修改 OrderController 类
Controller 添加一个接收远程 ajax 请求的方法,该方法后一个接收回调函数的参数.
/**** * 接收 jsonp 请求,响应 js 的字符串到客户端 * @param uid * @param callback * @return */ @RequestMapping("/loadOrderList03") @ResponseBody public String loadOrderList03(String uid,String callback){ System.out.println("uid="+uid); Order o1=new Order(); o1.setId("111"); o1.setTotal(123.0); o1.setDate("2018-10-10"); Order o2=new Order(); o2.setId("222"); o2.setTotal(1232.0); o2.setDate("2018-10-13"); Order o3=new Order(); o3.setId("333"); o3.setTotal(333.0); o3.setDate("2018-10-31"); List<Order> list = new ArrayList<>(); list.add(o1); list.add(o2); list.add(o3); //result 是需要响应到客户端的 js 代码 String result=callback+"("+JSON.toJSONString(list)+")"; return result; }
3.4 启动 order-sys 项目
4 修改 ajax-origin 项目
4.1 导入 juqery 函数库
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.js"></script>
4.2 发送请求
利用<script src="url?callback=doSomething"></script>发送请求
<script src="http://localhost:7070/order/loadOrderList03?uid=9999&callback=doCallback"></script>
4.3 定义 callback 回调函数
function doCallback(data){ //将 json 对象转化为字符串 var str=JSON.stringify(data); alert(str); }
4.4 启动 ajax-origin 测试
5jquery 对 jsonp 支持
function sendAjax(){ /* $.post("http://localhost:7070/order/loadOrderList02","uid=1234",function(data){ alert(data); }); */ $.getJSON("http://localhost:7070/order/loadOrderList03?callback=?","uid=1234", function(data){ //将 json 对象转化为字符串 var str=JSON.stringify(data); alert(str); }); }
3RMI 模拟服务器集群部署
3.1 建立 rmi-cluster-provider 项目
3.2 建立 UserService 接口
package com.bjsxt.service; import java.rmi.Remote; import java.rmi.RemoteException; /*** * 创建需要发布的服务对应的业务接口 * @author Administrator * Remote 接口用于标识其方法可以从非本地虚拟机上调用的接口。 */ public interface UserService extends Remote{ public String helloRmi(String name) throws RemoteException; }
3.3 建立 UserServiceImpl 实现类
package com.bjsxt.service.impl; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import com.bjsxt.service.UserService; /*** * 创建发布的服务对应的实现类 * @author Administrator * */ public class UserServiceImpl extends UnicastRemoteObject implements UserService { public UserServiceImpl() throws RemoteException { super(); // TODO Auto-generated constructor stub } @Override public String helloRmi(String name) throws RemoteException { // TODO Auto-generated method stub return "hello "+name; } }
3.4 发布集群服务
启动程序三次,每次启动修改端口号,实现服务的集群部署
package com.bjsxt.app; import java.rmi.Naming; import java.rmi.registry.LocateRegistry; import com.bjsxt.service.UserService; import com.bjsxt.service.impl.UserServiceImpl; public class ProviderApp { public static void main(String[] args) { try{ /**** * 完成远程服务的发布 */ //将远程服务发布在本地的 8888 端口 LocateRegistry.createRegistry(8888); //发布的远程服务的访问 url String name="rmi://localhost:8888/rmi"; //创建一个提供具体服务的远程对象 UserService userService = new UserServiceImpl(); //给提供远程服务的对象绑定一个 url Naming.bind(name, userService); System.out.println("=============发布 rmi 远程服务============"); }catch(Exception ex){ ex.printStackTrace(); } } }
4RMI 消费集群服务
4.1 建立 rmi-cluster-consumer 项目
4.2 拷贝 UserService 接口
4.3 实现集群服务消费
package com.bjsxt.app; import java.rmi.Naming; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ThreadLocalRandom; import com.bjsxt.service.UserService; public class ConsumerApp { public static void main(String[] args) { List<String> urls = new ArrayList<String>(); urls.add("rmi://localhost:7777/rmi"); urls.add("rmi://localhost:8888/rmi"); urls.add("rmi://localhost:9999/rmi"); String url =null; while(true){ try{ //通过随机的负载均衡算法,产生随机的访问地址 int index=ThreadLocalRandom.current().nextInt(urls.size()); //发布的远程服务的访问 url url = urls.get(index); //通过发布的远程服务的 url,获得远程服务的代理对象 UserService userService = (UserService) Naming.lookup(url); System.out.println("获得的远程服务的代理对象:" +userService.getClass().getName()); //通过远程服务的代理对象调用远程服务方法 String result = userService.helloRmi("===="+url+"======= rmi"); System.out.println("result="+result); Thread.sleep(3000); }catch (Exception e) { // TODO: handle exception urls.remove(url); //剔除不可用的服务的地址 e.printStackTrace(); } } } }
个人学习笔记,记录日常学习,便于查阅及加深,仅为方便个人使用。