springmvc4.3.19.RELEASE与cors

  最近把公司的一个整合了swagger2的rest工程的springmvc版本由3.2.16升级至4.3.19,测试过程中发现swagger-ui无法对接口进行测试了,从各方面查找原因并最终解决,写下此文记录过程。

确定为cors问题

  这是最重要的一步,确定了方向之后的解决方案网上还是很多的。

现象如下:
  1. 测试发现使用REST Client可以成功调用接口,无论是业务接口还是swagger2的apiDocs接口(以下简称apiDocs接口);
  2. swagger-ui可以获取接口列表,但是调用业务接口时会失败;
  3. 调用业务接口(POST)时,发现先进行了一次同url的OPTIONS请求,且状态码为403。

根据第三点的信息,查询了关于OPTIONS请求的知识,进了解到了cors的信息,并以此为方向渐渐的把问题解决了。

说明:swagger-ui调用业务接口使用的是ajax,所以需要处理跨域问题,而RESTClient调用不涉及到跨域问题,所以可以正常调用。

跨过的坑

1. 使用自定义过滤器(失败)

  项目本身有一个自定义的过滤器处理的CORS请求,代码如下(web.xml):

<filter>
	<filter-name>cors</filter-name>
	<filter-class>com.xxx.xxx.CorsFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>cors</filter-name>
	<url-pattern>/api/*</url-pattern>
</filter-mapping>
<filter-mapping>
	<filter-name>cors</filter-name>
	<url-pattern>/v2/api-docs</url-pattern>
</filter-mapping>

CorsFilter.java代码如下:

package com.xxx.xxx;

import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
 
public class CorsFilter implements Filter {
 
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}
 
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        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("Access-Control-Allow-Headers", "x-requested-with,Content-Type");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        filterChain.doFilter(servletRequest, servletResponse);
    }
 
    @Override
    public void destroy() {}
}

配合旧版本的springmvc食用没有问题,但是升级新版本springmvc后不好使了,但是并没有完全失效,那些走springmvc的业务接口无法调试,但是swagger2的apiDocs接口可正常调用,而且网上有文章说关于cors的解决方案就是加入这样的过滤器就可以了,导致我一度觉得不是cors的问题。
  其实原因是虽然在过滤器里处理的response,但是新版springmvc在DispatcherServlet中也进行了判断,判断请求如果是跨域的则读取spring关于cors的配置,如果没有配置的话就会将response的状态码置为403,所以过滤器无效了。 我这次在追踪源代码的核心目标就是“找到哪一行代码将状态置为403”,直接从“祖坟”DispatcherServlet开始打断点一步步跟进,没费多少时间就找到了。

2. 使用spring提供的过滤器(失败)

  网上有文章说可以通过配置spring提供的过滤器来解决,配置方式和上边web.xml中的代码相同,把filter-class改为org.springframework.web.filter.CorsFilter就可以了。但是在4.3.19版本中是不行的,因为CorsFilter这个类没有无参构造方法,启动项目会报错。参考的文章使用的是4.2版本,可能那个版本可以这么配置,不过我没有进行尝试。

3. 继承WebMvcConfigurerAdapter 类(失败)

代码如下

@Configuration
@EnableWebMvc
public class MyAdapter extends WebMvcConfigurerAdapter {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");
    }
}

无论是使用@Configuration和@EnableWebMvc还是使用@Component,还是在xml中配置bean,都无效…可能这是使用springboot才能生效的配置方式吧。

最终解决方案:在springmvc的配置文件中添加cors的相关配置

配置内容如下:

<mvc:cors>  
    <mvc:mapping path="/**"  
        allowed-origins="*"  
        allowed-methods="GET,POST,OPTIONS,DELETE"  
        allowed-headers="x-requested-with,Content-Type"  
        max-age="3600"/>  
</mvc:cors> 

其中allowed-origins默认就是"*",即所有其他域的请求都不拦截,此处可以不配,其他的可以参考.xsd文档,说明都很清楚;path是相对路径,不要加上servlet-mapping中的url-pattern,例如上方web.xml中配置了<url-pattern>/api/*</url-pattern>,那么在这个path中就不要在前边加上/api了。

PS:如果项目的接口较少或者针对特定的接口有cors需求,可以使用@CrossOrigin注解来处理,本文就不详细描述了。

本文参考了下方其他码友或组织的文章,特别感谢他们的分享:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值