跨域解决之CorsFilter与WebMvcConfigurer篇
平时在做前后端分离的项目开发的时候经常会遇到跨域问题,这里对解决方案做一个总结
先说一下跨域产生的原因:
跨域的原因其实很简单,就是浏览器的同源策略。同源策略是一种约定,同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。只要两个站点的域名或ip、端口、协议中的任意一个不同就认为是跨域。同源策略是为了保证web应用的安全性,但是会给开发造成麻烦。
解决方案
WebMvcConfigurer
这是spring官方给出的解决跨域的方法,
spring CorsSupport
@Configuration(proxyBeanMethods = false)
public class MyCorsConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
.allowedHeaders("*")
.allowedOrigins("")
.allowedMethods("*")
.allowCredentials(true)
.maxAge(3600);
}
};
}
}
这个方法十分的简单,但是在实际场景中使用起来可能会遇到一些麻烦,比如我们现在需要对请求路径进行拦截,要实现这个需求就要添加拦截器,现在我们在上面的代码上添加拦截器的代码
@Configuration(proxyBeanMethods = false)
public class MyCorsConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
// 跨域配置
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
.allowedHeaders(allowedHeader)
.allowedOrigins(allowedOrigins)
.allowedMethods("*")
.allowCredentials(true)
.maxAge(3600);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册的路由拦截器
registry.addInterceptor(new SaRouteInterceptor())
.addPathPatterns("/admin/**")
.excludePathPatterns("/admin/login");
}
};
}
}
上面这段代码看似很完美,其实是有问题的
使用上面这段代码时你会发现,被拦截的路径出现了跨域问题,而未被拦截的路径则可以正常请求,出现这种情况的原因则是由于请求在知道本次请求可以跨域之前就已经被拦下来了,自然就认为该站点不能允许跨域,就出现了跨域的情况。
CorsFilter
为了解决上面的情况,我们就要说到另一种解决跨域的方式了,即CorsFilter.
先上代码
@Configuration
public class CorsConfig {
@Value("${cors.allowedHeader}")
String allowedHeader;
@Value("${cors.allowedOrigins}")
String allowedOrigins;
//配置跨域
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
// 设置允许跨域请求的域名
config.addAllowedOrigin(allowedOrigins);
// 是否允许证书
config.setAllowCredentials(true);
// 设置允许的方法
config.addAllowedMethod("*");
// 允许任何头
config.addAllowedHeader(allowedHeader);
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**", config);
return new CorsFilter(configSource);
}
// 注册的路由拦截器
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SaRouteInterceptor())
.addPathPatterns("/admin/**")
.excludePathPatterns("/admin/login");
}
};
}
}
通过这两个bean,就可以实现跨域配置的同时进行路由拦截的需求。至于为什么CrosFilter可以做到Interceptor做不到的事情,是因为前者是过滤器后者是拦截器,过滤器是servlet提供的,而拦截器是spring提供的,过滤器的执行时机要早拦截器的,所以就可以在请求被拦截前允许跨域