跨域问题实战 2

跨域问题实战 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

猜你喜欢

转载自www.cnblogs.com/Krloypower/p/9277053.html
今日推荐