Part1:跨域问题剖析
1.跨域问题出现的原因
跨域问题:一般是A浏览器请求了非同源,例如B服务器的URI时,所导致的问题。
2.浏览器为什么要限制同源?
同源目的:是为了保证用户信息的安全,防止恶意的网站窃取数据。eg:比如银行用户的cookie信息。
3.同源的3个指标
所谓"同源"指的是"三个相同"。
1>协议相同
2>域名相同
3>端口相同
4.非同源受限制的3个行为
1>Cookie、LocalStorage 和 IndexDB 无法读取。
2>DOM 无法获得。
3>AJAX 请求不能发送。
其中第3条开发时碰到的最多。
5.解决非同源AJAX请求报错
同源政策规定,AJAX请求只能发给同源的网址,否则就报错。
除了架设服务器代理(浏览器请求同源服务器,再由后者请求外部服务),有三种方法规避这个限制。
1>JSONP
2>WebSocket
3>CORS
Part2:SpringMVC通过CORS协议解决跨域问题
1.CORS介绍
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。
它允许浏览器向跨源服务器,发出XMLHttpRequest
请求,从而克服了AJAX只能同源使用的限制。
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
2.方法1:Spring-自定义Fliter:在response中添加CORS响应头(Access-Control-Allow*)
3.方法2:SpringMVC4提供了非常方便的实现跨域的方法。在requestMapping中使用注解。
@CrossOrigin(origins = “http://kbiao.me”)
Part3:自己实际测试
1.跨域情境模拟:
前端index.html在电脑A上,页面中有个submit按钮来发送ajax请求。且请求url定位到后台对应Handler:http://192.168.0.218:8080/InsureService/crossOrigin/detail
;
后台服务器在电脑B上,Spring项目中书写一个测试controller接收HTTP请求。代码如下:
@Controller
@RequestMapping("/crossOrigin")
public class CrossOriginController {
@RequestMapping(value = "/detail", method = RequestMethod.POST)
@ResponseBody
public String savePayAndTrip(HttpServletRequest request){
String reqStr = HttpUtils.getReqeustData(request);
System.out.println("请求报文:" + reqStr);
return reqStr;
}//end method
}
2.跨域问题重现:
在上述情境准备下,前端请求的源
Origin为null
,后端源
Origin为http://192.168.0.218:8080
。两者不同源,所以前端的ajax请求,无法到达后台的Handler,也就不能被处理。(前端源为null,因为在本地电脑A直接在浏览器加载html文件发起请求导致。)
谷歌浏览器测试,截图: 1.跨域错误前端信息
2.跨域问题错误细节3.跨域问题解决:使用Spring的@CrossOrigin注解
@CrossOrigin注解,可以放在Controller类上,允许Controller中所有方法可被某个源
跨域请求;也可以放在Controller类中某一个方法上,指明当前方法可以被哪些源
跨域请求。
示例代码中:将@CrossOrigin加在Controller类上:
@Controller
@RequestMapping("/crossOrigin")
@CrossOrigin(origins = "*") //跨域核心配置
public class CrossOriginController {
@RequestMapping(value = "/detail", method = RequestMethod.POST)
@ResponseBody
public String savePayAndTrip(HttpServletRequest request){
String reqStr = HttpUtils.getReqeustData(request);
System.out.println("请求报文:" + reqStr);
return reqStr;
}//end method
}
分析:
浏览器针对'非简单请求'的跨域,会根据CORS协议在底层会发起两次request:
(1)使用HTTP协议OPTIONS方法,发起的预检请求
(preflight request);
(2)发起正常请求
谷歌浏览器测试结果: 1.OPTIONS预检请求
2.正常请求参考文章(干货满满)
1.阮一峰---浏览器同源政策及其规避方法
2.阮一峰---跨域资源共享 CORS 详解
3.Spring MVC通过CROS协议解决跨域问题
网友评论