CORS设置跨域不生效排查之路

结构:springboot2.x版本

CORS(跨域资源共享),可以把其当做是通过设置http响应头来允许不同协议、ip、port可以跨域请求。

在springboot中,一般常采用两种方式实现CORS:

一,通过拦截器的方式,通过继承WebMvcConfigurationSupport,重写addCorsMappings方法,具体代码如下:

    @Override
    protected void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
        .allowCredentials(true)
        .allowedHeaders("*")
        .allowedMethods("*")
        .allowedOrigins("*");
        super.addCorsMappings(registry);
  }

二,通过过滤器的方式,具体代码如下:

    @Configuration
    public class GlobalCorsConfig {
        @Bean
        public CorsFilter corsFilter() {
            CorsConfiguration config = new CorsConfiguration();
            //开放哪些ip、端口、域名的访问权限,星号表示开放所有域
            config.addAllowedOrigin("*");
            //是否允许发送Cookie信息
            config.setAllowCredentials(true);
            //开放哪些Http方法,允许跨域访问
            config.addAllowedMethod("GET","POST", "PUT", "DELETE");
            //允许HTTP请求中的携带哪些Header信息
            config.addAllowedHeader("*");
            //添加映射路径,“/**”表示对所有的路径实行全局跨域访问权限的设置
            UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
            configSource.registerCorsConfiguration("/**", config);
            return new CorsFilter(configSource);
        }
  }

接下来,我们对上述两种方式,存在失效情况分别描述:

方式1,可能失效的情况如下:

第一: 如果一个项目中存在多个WebMvcConfigurationSupport或者WebMvcConfigurerAdapter,可能会导致设置的允许跨域addCorsMappings不生效。

第二:如果一个项目中存在多个自定义的拦截器,执行顺序导致设置跨域失效,伪代码如下:

如上,执行顺序是从上至下的,导致业务拦截器先执行,本应该跨域拦截器在业务拦截器前执行。

 

方式2,使用过滤器的方式,我们应该知道过滤器是先与拦截器执行的。所以,这是我们就不要考虑到和拦截器冲突问题。其实,我项目中采用的就是这种方式,过滤器设置CORS允许跨域请求,拦截器处理业务代码(问题出现在拦截器中)。

出现CORS设置不生效时,程序的结构是,存在GlobalCorsConfig的设置就是方式二的设置,然后就是一个业务的拦截器,伪代码如下:

拦截器中代码也很简单,就是验证请求中的key是否合法,合法则不拦截,不合法拦截并响应,代码如下:

也就是采用response流输出的时候,调用了reset()函数,还记得最开头的时候,CORS设置可以简单的理解为对response设置请求头,或者你也会看到另外一种写法,如下:(也是对CORS设置的一种方式)

        HttpServletResponse response = (HttpServletResponse) res;
        String allowedOriginsUrl = configurationUtil.getAllowedOriginsUrl();
        String[] allowedOriginsUrlArr = allowedOriginsUrl.split(",");
        for(String temp : allowedOriginsUrlArr){
            response.setHeader("Access-Control-Allow-Origin",temp); // 允许的来源
        }
        response.setHeader("Access-Control-Allow-Credentials", "true"); // 是否允许证书
        response.setHeader("Access-Control-Allow-Methods", "*"); // 允许的请求方式
        response.setHeader("Access-Control-Max-Age", "3600"); // 预检请求的有效期
        response.setHeader("Access-Control-Allow-Headers", "*");
        chain.doFilter(req, res);

由此,可以更清楚的看出,其实就是response设置了头部header,来实现允许跨域请求。那上面的问题就很明显了,到过滤器的时候,设置了response的响应头允许跨域,但到了拦截器的时候,又把reponse重置了,导致设置的不生效。

 

结论:

1.采用CORS方式,设置允许跨域时,推荐filter的方式,这种方式先于拦截器执行。

2.如果遇到不生效的情况下,我们先采用一种最简单的方式来设置允许跨域,如果可行,放在你项目中不能使用,需要排查是否存在冲突问题了

3.解决跨域还有其他的多种方案(推荐采用代理nginx、网关方式)

 

 

  • 11
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Java后端cors跨域设置白名单可以通过以下步骤实现: 1. 在web.xml文件中添加CorsFilter过滤器。 2. 在CorsFilter过滤器中设置允许跨域的域名白名单,可以使用通配符*表示允许所有域名跨域访问。 3. 在CorsFilter过滤器中设置允许跨域的请求方法,例如GET、POST等。 4. 在CorsFilter过滤器中设置允许跨域的请求头,例如Content-Type、Authorization等。 5. 在CorsFilter过滤器中设置允许跨域的响应头,例如Access-Control-Allow-Origin、Access-Control-Allow-Methods等。 具体实现可以参考以下代码: ``` public class CorsFilter implements Filter { private String allowOrigin; private String allowMethods; private String allowCredentials; private String allowHeaders; private String exposeHeaders; @Override public void init(FilterConfig filterConfig) throws ServletException { allowOrigin = filterConfig.getInitParameter("allowOrigin"); allowMethods = filterConfig.getInitParameter("allowMethods"); allowCredentials = filterConfig.getInitParameter("allowCredentials"); allowHeaders = filterConfig.getInitParameter("allowHeaders"); exposeHeaders = filterConfig.getInitParameter("exposeHeaders"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) servletResponse; HttpServletRequest request = (HttpServletRequest) servletRequest; if (StringUtils.isNotBlank(allowOrigin)) { response.setHeader("Access-Control-Allow-Origin", allowOrigin); } if (StringUtils.isNotBlank(allowMethods)) { response.setHeader("Access-Control-Allow-Methods", allowMethods); } if (StringUtils.isNotBlank(allowCredentials)) { response.setHeader("Access-Control-Allow-Credentials", allowCredentials); } if (StringUtils.isNotBlank(allowHeaders)) { response.setHeader("Access-Control-Allow-Headers", allowHeaders); } if (StringUtils.isNotBlank(exposeHeaders)) { response.setHeader("Access-Control-Expose-Headers", exposeHeaders); } filterChain.doFilter(request, response); } @Override public void destroy() { } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值