美文网首页
服务端支持跨域

服务端支持跨域

作者: songwl | 来源:发表于2018-04-11 15:59 被阅读0次

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

服务端支持跨域方案:

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

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

相关文章

  • 被调用方解决

    被调用方解决 1、被调用方解决 – 支持跨域 (1)被调用方支持跨域解决方案 服务端实现 Nginx配置 Apac...

  • 服务端支持跨域

    大背景:前后端分离后,项目分开部署,域名不一致,ajax请求时需要解决跨域问题。 服务端支持跨域方案: 1、spr...

  • Vue 创建博客前端-DAY2-文章列表

    服务端支持跨域 在 nest 项目 main.ts 中加入 app.enableCors()。 使用 axios ...

  • ajax

    ajax 跨域 跨域:http 协议 域名 端口 三者只要有一个不同,就是跨域 服务端解决跨域: res.setH...

  • 跨域请求时会遇到的坑

    跨域请求如果需要服务端支持时,最好的做法是直接在nginx中配置,这样最灵活。如果跨域请求中包含了自定义字段的时候...

  • nigix服务端支持跨域

    在nginx.conf中配置 http { ...... add_header Access-Control-Al...

  • 在 AJAX 中开启 CROS

    什么是 CROS cros 是 xhr 中的高级特性,支持跨域请求。 服务端需要在响应头中添加下面的字段来支持其他...

  • 前端跨域

    CORS跨域 1.CORS跨域-服务端设置,前端直接调用说明:后台允许前端某个站点进行访问 2.JSONP跨域-前...

  • 跨域解决方向

    跨域解决方向 1、被调用方解决 基于支持跨域的解决思路 基于http协议支持跨域方面的一些规定 在响应头中添加支持...

  • spring cloud gateway跨域冲突功能的开发

    gateway可以实现支持跨域功能,但如果下游也支持跨域,会出现跨域冲突。如何解决该问题,gateway对外输出相...

网友评论

      本文标题:服务端支持跨域

      本文链接:https://www.haomeiwen.com/subject/xhhzhftx.html