跨域问题实战 2
背景
由于整个项目提供出去的API都不是跨域的只是个别是需要跨域的,所以再上一次跨域问题实战中,自己是直接再controller层其中需要提供出去跨域的方法里设置了HttpServletResponse.setHeader("Access-Control-Allow-Origin","*")。而且上次提供出去的只是一次简单的get请求,而不是复杂请求。但是呢,这次的需求是记录用户行为日志的一次跨域请求,也就是说是一次post请求。其中就涉及到http请求的Content-Type中application/json和application/x-www-form-urlencoded。还涉及到springMVC中的@RequestBody这个注解。其中这些问题,就下一篇博客再详细记录。因为涉及到post中的application/json所以就涉及到跨域的复杂请求。
问题重现
由于ajax默认的contentType是application/x-www-form-urlencoded。所以自己对这次请求设置的是application/json
代码如下
var data = {
"userId" : 20142100122,
"userOperationStep" : 2,
"appPlatform": "android",
"app" : 0,
"videoId":123123
};
$.ajax({
url : 'http://xxxxxx/xxxxc/xxx/vippromotion',
type : 'POST',
dateType : 'json',
contentType : 'application/json',
data:JSON.stringify(data),
success : function(msg){
console.log(msg);
}
})
由于自己只想让该接口可以被进行跨域操作所以自己再controller层是单独设置的跨域请求的
部分代码如下
public Json vippromotion(@RequestBody VipPromotionLog vipPromotionLog, HttpServletResponse response){
response.setHeader("Access-Control-Allow-Headers","Origin, X-Requested-With, Content-Type, Accept");
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Allow","POST");
response.setHeader("Access-Control-Allow-Credentials ", "true");
.......
}
看清楚自己这里设置了Access-Control-Allow-Headers允许了复杂请求,但是却出现如下错误
如图一
但是Ajax请求却没有失败。如图二
排查
由于自己再该接口中设置了允许复杂请求,但是却根本没有进来,所以并不是跨域代码错误。这里就得说一下什么是复杂请求了。复杂请求是会进行两次请求得,一次是预请求,一次是真正得请求。 从上面得例子可以看出,自己只是对真正得请求进行跨域处理,但是却没有对预请求进行跨域处理。所以导致跨域失败。
解决
设置过滤器,对每次进行进行跨域处理代码如下
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse res, FilterChain filterChain) throws IOException, ServletException {
System.out.println("doFilter--------------start");
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Allow","POST");
response.setHeader("Access-Control-Allow-Headers","Origin, X-Requested-With, Content-Type, Accept");
response.setHeader("Access-Control-Allow-Credentials ", "true");
System.out.println("doFilter--------------end");
filterChain.doFilter(servletRequest, res);
}
web.xml中得我就不贴了。
运行项目发起请求,请求处理如下图三:
看到了没有两次请求。
然后我们再发起一次请求来看一下,结果如下图四
只有一次请求,这是因为设置了 response.setHeader("Access-Control-Max-Age", "3600");6分钟内不用再发起预请求。
防止
如果是一个单独给外界提供接口得项目得话,我建议设置一个跨域处理得过滤器。如果只是一个项目中一两个接口是提供给别人得,别人是跨域操作得话,尽量是简单请求。就是用ajax中默认得参数application/x-www-form-urlencoded