结构:springboot2.x版本
CORS(定制小程序开发跨域资源共享),定制小程序开发可以把其当做是通过设置http定制小程序开发响应头来允许不同协议、ip、port定制小程序开发可以跨域请求。
在springboot中,定制小程序开发一般常采用两种方式实现CORS:
一,定制小程序开发通过的方式,通过继承WebMvcConfigurationSupport,重写addCorsMappings方法,具体代码如下:
@Override
void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
.allowedHeaders("*")
.allowedMethods("*")
.allowedOrigins("*");
super.addCorsMappings(registry);
}
二,通过过滤器的方式,具体代码如下:
@
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、网关方式)