服务端支持跨域

大背景:前后端分离后,项目分开部署,域名不一致,ajax请求时需要解决跨域问题。

服务端支持跨域方案:

1、spring早已经支持跨域的配置。

服务端支持跨域_第1张图片

2、@CrossOrgin注解方式,支持配置到controller或者具体的方法上。不多解释注解的参数。

说明:我理解的是,1和2方案都是通过spring提供的CorsFilter做了拦截。


3、spring 拦截器方式 

public classCrossDomainInterceptorextendsHandlerInterceptorAdapter {

@Override

   public booleanpreHandle(HttpServletRequest request,HttpServletResponse response,Object handler)throwsException {

if(RequestMethod.OPTIONS.name().equalsIgnoreCase(request.getMethod())) {

response.addHeader("Access-Control-Allow-Origin",request.getHeader("Origin"));

           response.addHeader("Access-Control-Allow-Methods","GET,POST,PUT,OPTIONS,DELETE");

           response.addHeader("Access-Control-Max-Age","1800");

           response.addHeader("Access-Control-Allow-Headers","Content-Type,x-requested-with,access-token");

           response.addHeader("Access-Control-Allow-Credentials","true");

            //response.setStatus(HttpStatus.SC_OK);

            return false;

       }

return true;

   }

}

4、自定义Filter,然后在XML配置 filter。

public classCrossDomainFilterimplementsFilter{

@Override

   public voidinit(FilterConfig filterConfig)throwsServletException {

    }

@Override

   public voiddoFilter(ServletRequest servletRequest,ServletResponse servletResponse,FilterChain filterChain)throwsIOException,ServletException {

if(servletRequestinstanceofHttpServletRequest && servletResponseinstanceofHttpServletResponse) {

HttpServletRequest request = (HttpServletRequest) servletRequest;

           HttpServletResponse response = (HttpServletResponse) servletResponse;

            if(CorsUtils.isCorsRequest(request)) {

log.info(request.getRequestURL().toString() +" options request into CrossDomainFilter");

                if(!processRequest(request,response) || CorsUtils.isPreFlightRequest(request)) {

return;

               }

            }

filterChain.doFilter(request,response);

       }else{

filterChain.doFilter(servletRequest,servletResponse);

       }

    }

private booleanprocessRequest(HttpServletRequest request,HttpServletResponse response) {

booleanisValid =false;

       String curOrigin = request.getHeader("Origin");

       String[] domains ="http://localhost:8080,http://localhost:8090".split(",");

        if(domains.length>0) {

for(String domain : domains) {

if(curOrigin.equals(domain)) {

response.addHeader("Access-Control-Allow-Origin",domain);

                   response.addHeader("Access-Control-Allow-Methods","GET,POST,PUT,OPTIONS,DELETE");

                   response.addHeader("Access-Control-Allow-Headers","Content-Type, x-requested-with, access-token");

                   response.addHeader("Access-Control-Max-Age","1800");

                   response.addHeader("Access-Control-Allow-Credentials","true");

                   isValid =true;

                    break;

               }

            }

        }

returnisValid;

   }

@Override

   public voiddestroy() {

    }

}

以上四种方案好像所以的看上去都是那么简单,没什么难度。我一开始也是这样认为的。然而。。。。

过程中遇到如下几个问题。

1)我们希望domain可支持的域名是可以动态配置,通过公司的配置系统可以动态获取allowOrigins。那么方案1被我抛弃了,因为xml里配置无法动态生效。因为是基于全局配置,就没有考虑方案2.

2)我用了spring拦截器方式CrossDomainInterceptor,或者CrossDomainFilter extends OncePerRequestFilter。就是这个过程都被spring管理着。但是出现了状况:

A、请求依然403. 原因:经过各种尝试发现,Access-Control-Allow-Credentials、Access-Control-Allow-Headers有设置时,Access-Control-Allow-Origin 不要设置成 *。并且Access-Control-Allow-Headers 需要和前端传上来的header 参数名匹配上,否则很容易403.

B、解决了测试环境的403之后,有同学又反应本地开发环境出现“Invalid Cors Request”。找了4个同学本地postman请求服务端接口,2个同学反应没有问题,2个同学反应出现“Invalid Cors Request”。这里很难理解,postman里的请求就是简单的接口测试,不存在跨域问题,无法理解。解决方案:在网上有看到帖子说是因为多个filter顺序问题,其他filter导致了跨域filter出现了问题。。。(确实项目还集成了其他需要用到过滤器的地方,如:安全框架接入)

基于以上出现的状况,我决定从头开始,回归本质。首先跨域就是需要对浏览器PreflightRequest(Options预检查请求)。进行过滤。那么就定义一个java filter吧。filter不再继承OncePerRequestFilter(毕竟让spring控制后自己就不会关注那么多了,这未必是好事)。然后把filter配置到web.xml(可以决定filter的顺序,也为了解决以上最后提到的filter顺序问题)。代码参考方案4。结果嘛,自然是一切就那么好起来了。

Access-Control-Allow-Headers 需要支持前端传上来的参数。

Access-Control-Allow-Credentials、Access-Control-Allow-Headers有设置时,Access-Control-Allow-Origin 不要设置成 *,只能支持一个。

注意过滤器的顺序问题。(即,你需要先做哪一步过滤)


引用一些参考的文章:

https://blog.csdn.net/dalangzhonghangxing/article/details/52911230

https://blog.csdn.net/pinebud55/article/details/60874725

https://segmentfault.com/a/1190000012469713

你可能感兴趣的:(服务端支持跨域)