最近项目里需要处理跨域请求,遇到了一些问题,中间走了很多坑,深挖了很多细节,受益良多。
cors在跨域解决方案中算是很好用的,网上资料一大堆,只需要在服务器端进行配置即可。
配置方法网上也很多,我简单记录下,
主要用到cors-filter-1.7.jar 和java-property-utils-1.9.jar 这两个jar包,其实cors-filter jar包最新的已经出到2.5了
不过1.7的也能用。然后在web.xml里面配置一个filter
<span style="white-space:pre"> </span><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, XRequestedWith, Content-Type, LastModified</param-value>
</init-param>
<init-param>
<param-name>cors.exposedHeaders</param-name>
<param-value>SetCookie</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>
普通的ajax请求测试时没有问题的,但是 我在上传文件跨域的时候遇到个莫名其妙的问题,用chrome上传不好使,用firefox好使。 我
配置的没有问题,代码也没什么问题,那么我猜测问题可能是浏览器的。 通过开发工具抓包,我发现chrome的请求内容是这样的
下面的是firefox的
可以看到chrome浏览器多了个access-control-allow-headers 头,而firefox则没有。通过Fiddler模拟请求,发现就是这个
属性的问题,去掉的话,就能发送成功。 我又上cors的官网,找到了这么个图片
cors过滤器的过滤流程清晰易懂,看起来还是挺好理解的,后来我又查看了源码,发现在判断access-control-allow-headers头的时候会根据xml里面cors.supportedHeaders配置的进行比对,如果这个头没有配置就返回403,我配置了,但是和浏览器配置的不一样我配置的是ContentType,但浏览器发送的是Content-Type,多了个横杠 快哭了,看起来一个小问题,水却很深啊。 在上图中可以看到,会先判断是不是带origin头,如果带的话,才会判断access-control-allow-headers头,这是个自定义的头信息。
在调试的过程中发现springmvc 默认是不支持options 请求, 要想支持这个请求,需要在web.xml的DispatcherServlet 增加
<init-param>
<param-name>dispatchOptionsRequest</param-name>
<param-value>true</param-value>
</init-param>
同时,在RequestMapping中需要知道method是options的,这样springmvc就可以接收到options请求。
options请求比较特殊,是个透明请求,一般在跨域的时候浏览器会先发个options请求,询问服务器是否支持跨域, access-control-allow-method表示后面实际发送数据的请求方法, 这个方法名需要包含在cors.supportedMethods 的配置。
CORS可以分成两种:
- 简单请求
- 复杂请求
一个简单的请求大致如下:
- HTTP方法是下列之一
-
HEAD
-
GET
-
POST
-
- HTTP头包含
-
Accept
-
Accept-Language
-
Content-Language
-
Last-Event-ID
-
Content-Type
,但仅能是下列之一-
application/x-www-form-urlencoded
-
multipart/form-data
-
text/plain
-
-
任何一个不满足上述要求的请求,即被认为是复杂请求。一个复杂请求不仅有包含通信内容的请求,同时也包含预请求(preflight request)。