【SpringBoot】SpringBoot配置CORS跨域和遇到的问题
这里记录一次使用SpringBoot项目配置CORS跨域的写法和中间遇到的问题。使用SpringBoot配置CORS跨域的方式有三种,下边分别介绍下。一、方式一:使用@CrossOrigin注解如果想要对某一接口配置 CORS,可以在方法上添加 @CrossOrigin 注解:@CrossOrigin(origins = {"http://localhost:8080", "null"})@Req
这里记录一次使用SpringBoot项目配置CORS跨域的写法和中间遇到的问题。
使用SpringBoot配置CORS跨域的方式有三种,下边分别介绍下。
一、方式一:使用@CrossOrigin注解
如果想要对某一接口配置 CORS,可以在方法上添加 @CrossOrigin 注解:
@CrossOrigin(origins = {"http://localhost:8080", "null"})
@RequestMapping(value = "/test", method = RequestMethod.GET)
public String greetings() {
return "test";
}
如果想对一系列接口添加 CORS 配置,可以在类上添加注解,对该类声明所有接口都有效:
@CrossOrigin(origins = {"http://localhost:8080", "null"})
@RestController
@SpringBootApplication
public class SpringBootCorsTestApplication {
......
}
二、方式二:添加全局配置,需要加一个配置类
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
// .allowedOrigins("*")
.allowedOriginPatterns("*")// 设置允许跨域请求的域名
.allowedHeaders("*")// 设置允许的请求头
.allowCredentials(true)// 是否允许证书
.allowedMethods("*")// 允许的方法
.maxAge(3600);// 跨域允许时间
}
}
注意,当我项目里使用的springboot的版本是2.1.2.RELEASE时,使用allowedOrigins(“*”)没有问题,但是当版本改为2.4.4后会提示报错如下:
When allowCredentials is true, allowedOrigins cannot contain the special value “*” “since that cannot be set on the “Access-Control-Allow-Origin” response header. To allow credentials to a set of origins, list them explicitly or consider using"allowedOriginPatterns” instead.
翻译:当allowCredentials为true时,allowedOrigins不能包含特殊值"* “,因为它不能在” Access-Control-Allow-Origin "响应头中设置。要允许一组起源的凭证,明确地列出它们,或者考虑使用“allowedOriginPatterns”代替。
所以将.allowedOrigins("*")
换成.allowedOriginPatterns("*")
后解决。
三、方式三:使用Filter过滤器进行配置
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
// config.addAllowedOrigin("*");
config.addAllowedOriginPattern("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config); // CORS 配置对所有接口都有效
return new CorsFilter(source);
}
四、原理剖析
无论是通过哪种方式配置 CORS,其实都是在构造 CorsConfiguration。 一个 CORS 配置用一个 CorsConfiguration类来表示,它的定义如下:
public class CorsConfiguration {
private List<String> allowedOrigins;
private List<String> allowedMethods;
private List<String> allowedHeaders;
private List<String> exposedHeaders;
private Boolean allowCredentials;
private Long maxAge;
}
Spring 中对 CORS 规则的校验,都是通过委托给 DefaultCorsProcessor 实现的。
DefaultCorsProcessor 处理过程如下:
- 判断依据是 Header 中是否包含 Origin。如果包含则说明为 CORS请求,转到 2;否则,说明不是 CORS 请求,不作任何处理。
- 判断 response 的 Header 是否已经包含 Access-Control-Allow-Origin,如果包含,证明已经被处理过了, 转到 3,否则不再处理。
- 判断是否同源,如果是则转交给负责该请求的类处理。
- 是否配置了 CORS 规则,如果没有配置,且是预检请求,则拒绝该请求,如果没有配置,且不是预检请求,则交给负责该请求的类处理。如果配置了,则对该请求进行校验。
校验就是根据 CorsConfiguration 这个类的配置进行判断:
- 判断 origin 是否合法
- 判断 method 是否合法
- 判断 header是否合法
- 如果全部合法,则在 response header中添加响应的字段,并交给负责该请求的类处理,如果不合法,则拒绝该请求。
五、遇到的问题
刚开始我的拦截器是通过实现WebMvcConfigurer接口,然后重写addCorsMappings(CorsRegistry registry)方法添加跨域设置的,也就是上边的方式二,但是我项目里有自定义的拦截器,在所有请求前加了登陆状态的判断(会获取header里的自定义token进行判断)。这个时候就会出现问题,在获取自定义header时为null,前端一直报跨域问题:
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
原因是请求经过的先后顺序问题,请求会先进入到自定义拦截器中,而不是进入Mapping映射中,所以返回的头信息中并没有配置的跨域信息,浏览器就会报跨域异常。所以改为使用Filter的方式配置CORS跨域,解决问题。
更多推荐
所有评论(0)