理论基础
Cors跨域是什么?Cors的英文全称是Cross-origin Resource Sharing,意思是跨域资源共享。它允许浏览器向非同源服务器发送XMLHttpRequest请求,能够像访问同源本地服务器一般。Cors需要浏览器和服务器同时支持,现在的主流浏览器(Google/IE/FireFox/360)一般都支持跨域的,所以关键在于服务器端实现跨域问题,才能真正实现跨域通信。
跨域请求的分类
跨域分为2种请求:简单请求和非简单请求
1简单请求是什么呢?
同时满足以下两种条件的,就是简单请求
(1) 请求方法是以下三种方法之一:
HEAD
GET
POST
(2)HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
2非简单请求又是什么呢?
只要一条不满足,就是非简单请求。这是因为浏览器端对于这2种请求是不一样的,详细看阮一峰跨域资源共享CORS详解博客。非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。
Header字段含义
(1)Access-Control-Allow-Origin
它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。关键的是Access-Control-Allow-Origin字段,表示http://api.bob.com可以请求数据。该字段也可以设为星号,表示同意任意跨源请求。如下:Access-Control-Allow-Origin: *
(2)Access-Control-Allow-Methods
该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。
(3)Access-Control-Allow-Headers
如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。
(4)Access-Control-Allow-Credentials
它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。
(5)Access-Control-Max-Age
该字段可选,用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此期间,不用发出另一条预检请求。
实战
编写一个过滤器,实现javax.servlet.Filter接口并覆写它的doFilter方法如下
在web.xml文件中,我配置过滤器的规则,所有以/security/开头的做跨域处理。
刚刚开始我也踩了很多坑,没仔细看Header设置了些什么参数,也不知道干啥用。于是出现了一种预检错误。XMLHttpRequest cannot load URL路径地址 Request header field Content-Type is not allowed by Access-Control-Allow-Headers in prelight response。见如下图:
本人英文很菜,原理内功也不深,后来查阮一峰博客,其中有一段话:如果浏览器否定了"预检"请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。原因就在这里。因为我这发送的是application/json,它是一个非简单请求,会存在预检,很快发现问题了。
改写前:
改写后:
这不是错误么?明显它是一个逗号分隔的字符串,我怎么写成了*,脑子短路了。
总结
一般来说后台之间相互调用不存在跨域的问题,一旦和前端打交道,准确的说是和浏览器打交道,这个时候就需要解决跨域问题了。解决办法也很多,Cors、JSONP、WebSocket等,但是我更倾向Cors,因为它几乎支持Http的所有请求,JSONP只能用于GET请求。然而后台Cors的解决办法也很多,一种是采用过滤器配置的方式,一种是采用CrossOrigin注解的方式,Spring MVC 4.2开始增加支持跨域访问。我觉得更重要的是要理解它的原理和机制,才能不会掉坑里,比如:Content-Type:application/json它是非简单请求,我之前还真不知道。所以做技术还是要深入,只会用是不够的,阅读源码和原理,多逛大牛技术博客,是非常有益的。这篇流水账先记到这里。
参考资料
1 阮一峰 跨域资源共享 CORS 详解
http://www.ruanyifeng.com/blog/2016/04/cors.html
2 阮一峰 浏览器同源政策及其规避方法
http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
3 tianjun2012的专栏 SpringMVC前后台分离,跨域问题的解决方法
https://blog.csdn.net/tianjun2012/article/details/50598551
领取专属 10元无门槛券
私享最新 技术干货