springboot解决跨域问题
基本概念:
1、同源策略:是指协议、域名、端口都要相同,只要有一个不相同,就是跨域。
注:跨域限制访问是浏览器的限制
2、CORS:跨域资源共享,这是一种机制,允许web服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。
注:很赞的一篇介绍CORS的文章
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
问题演变和改进过程
1、前后端分离开发,后端使用springboot框架提供http接口,因为没有满足同域条件,从而出现了跨域访问问题。
2、首先使用的解决方案是实现这个WebMvcConfigurer这个接口,实现addCorsMappings这个方法。
@Override
public void addCorsMappings(CorsRegistry registry) {
// 设置允许跨域的路径
registry.addMapping("/**")
// 设置允许跨域请求的域名
.allowedOrigins(GlobalConstants.ALLOW_HOSTS)
.allowedHeaders("*")
// 是否允许证书 不再默认开启
.allowCredentials(true)
// 设置允许的方法
.allowedMethods("*")
// 跨域允许时间
.maxAge(3600);
}
3、通过这样的配置的确解决了跨域问题,但是呢,因为需要在服务端配置权限验证,就是控制访问http接口的权限,主要是从cookie中拿取一个字段进行校验,因此配置了一个权限验证拦截器,配置了这个有出事了。。。因为拦截器的执行顺序和addCorsMappings这个方法的执行有顺序问题,当请求被拦截后,addCorsMappings这个方法所设置的跨域配置没起作用,从而又出现了跨域问题。。这时候该怎么办呢?
借助于过滤器来设置跨域问题,让跨域的设置在拦截器的权限验证之前,过滤器的设置如下:
@Component
@Order(1)
@WebFilter(urlPatterns = "/**")
public class CORSFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
String orign = httpServletRequest.getHeader("Origin");
if(Arrays.asList(GlobalConstants.ALLOW_HOSTS).contains(orign)) {
httpServletResponse.setHeader("Access-Control-Allow-Origin", orign);
httpServletResponse.setHeader("Access-Control-Allow-Methods", "*");
httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpServletResponse.setHeader("Access-Control-Allow-Headers", "Content-Type,Accept,token,X-Requested-With");
httpServletResponse.setHeader("Access-Control-Max-Age", "3600");
}
chain.doFilter(request, response);
}
}
4、以为这样就完事了?又踩到了一个坑。涉及到tomcat的版本问题。报错如下:(这个错误是启动时tomcat报的错误,但是要把这个错误打出来,需要进行启动时logging.properties的配置)。
错误信息:
java.lang.AbstractMethodError: com.jd.trade.o2n.soa.web.filter.CORSFilter.init(Ljavax/servlet/FilterConfig;)V
大概意思是init是抽象方法,没有实现。本地的Filter接口用的是tomcat9版本的,init和destory方法都提供了默认的实现了,不需要额外实现。看上面的init和destory方法,之前代码中是没有的,只提供了doFilter的实现。但是在预发布发时,使用的是tomcat8,这两个方法没有提供默认实现,启动时tomcat启动不起来。比较难受的是tomcat的错误日志一直找不到地方看。结果参考网上的说法,才把tomcat的错误日志打印出来,从而发现了问题。习惯看catlina中的日志,但是没啥关键信息。
总结:上面是踩过的一些坑,但是呢,也学到了很多。愿与大家共勉。