描述
跨域是后端接口必须处理的问题,新搭建的服务使用SpringBoot
的版本为2.7.0
。使用postman请求接口时不带origin
,接口都是可以正常返回的,
当加上了origin
后,就报错了,报错信息如下:
1
2
3
4
5
6
7
8
9
10
java.lang.IllegalArgumentException: 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.
at org.springframework.web.cors.CorsConfiguration.validateAllowCredentials(CorsConfiguration.java:475)
at org.springframework.web.cors.CorsConfiguration.checkOrigin(CorsConfiguration.java:579)
at org.springframework.web.cors.DefaultCorsProcessor.checkOrigin(DefaultCorsProcessor.java:174)
at org.springframework.web.cors.DefaultCorsProcessor.handleInternal(DefaultCorsProcessor.java:116)
at org.springframework.web.cors.DefaultCorsProcessor.processRequest(DefaultCorsProcessor.java:95)
at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:87)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
我们初始的跨域设置是这样的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Configuration
@EnableWebMvc
public class CORSConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(true)
.allowedHeaders("*")
.maxAge(1800L);
}
}
根据报错的信息提示,我们将allowedOrigins
修改为allowedOriginPatterns
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Configuration
@EnableWebMvc
public class CORSConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(true)
.allowedHeaders("*")
.maxAge(1800L);
}
}
正常情况下,启动应用访问,应该就解决了。当还是报相同的错误。我们联系了前端和运维,在js
和nginx
端都作了处理,依然无济于事。
还发现一个诡异的问题,无论我本地如何上述跨域设置,都报上面相同的错误。
因为线上要使用,被迫用其他解决方案紧急处理掉。后来发现神队友居然在
springboot
的启动类中又写了个跨域的设置Bean
。所以 出现如下情况也就不奇怪了,再次提示务必规范编码,不然排查错误都能把人整懵逼。-_-||
于是我本地debug
设置了断点在CorsConfiguration.java:475
的CorsConfiguration.validateAllowCredentials
方法。
发现一次请求进了两次断点。其中有一次if (this.allowCredentials == Boolean.TRUE &&
this.allowedOrigins != null && this.allowedOrigins.contains(ALL))
判断是通过的,显示this.allowedOrigins
的值为”*”;
所以就抛了这异常java.lang.IllegalArgumentException: 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
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* Validate that when {@link #setAllowCredentials allowCredentials} is true,
* {@link #setAllowedOrigins allowedOrigins} does not contain the special
* value {@code "*"} since in that case the "Access-Control-Allow-Origin"
* cannot be set to {@code "*"}.
* @throws IllegalArgumentException if the validation fails
* @since 5.3
*/
public void validateAllowCredentials() {
if (this.allowCredentials == Boolean.TRUE &&
this.allowedOrigins != null && this.allowedOrigins.contains(ALL)) {
throw new IllegalArgumentException(
"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.");
}
}
其他解决方案
- 降级
springboot
的版本到2.3.x
(推荐)之前我们使用
springboot
的2.3.12.RELEASE
时,设置跨域是不能allowedOriginPatterns
的,接口也是正常,可以使用maven
管理pom.xml
先降级到2.3.x
的版本。 - 将
CorsConfiguration.java
中CorsConfiguration.validateAllowCredentials
方法的抛异常注释掉 因为我们目前用的是2.7.0
版本,并且使用了多数据源特性,使用maven
降级后启动会报错。修改多数据源的代价还是很大的,所以我选择重写validateAllowCredentials
方法。- 首先在项目中新建
org.springframework.web.cors
包 - 在
org.springframework.web.cors
包中新建CorsConfiguration.java
类 - 将
CorsConfiguration.class
中的代码复制到本地中,修改validateAllowCredentials
方法,注释throw new IllegalArgumentException(When allowCredentials is true, allowedOrigins cannot contain the special value ...)
- 启动项目访问解决了。
java
加载类采用就近原则,故可以进行覆盖。
- 首先在项目中新建