首页 springboot升级2.7后,无法设置跨域的问题
文章
取消

springboot升级2.7后,无法设置跨域的问题

描述

跨域是后端接口必须处理的问题,新搭建的服务使用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);

    }
}

正常情况下,启动应用访问,应该就解决了。当还是报相同的错误。我们联系了前端和运维,在jsnginx端都作了处理,依然无济于事。

还发现一个诡异的问题,无论我本地如何上述跨域设置,都报上面相同的错误。

因为线上要使用,被迫用其他解决方案紧急处理掉。后来发现神队友居然在springboot的启动类中又写了个跨域的设置Bean。所以 出现如下情况也就不奇怪了,再次提示务必规范编码,不然排查错误都能把人整懵逼。-_-||

于是我本地debug设置了断点在CorsConfiguration.java:475CorsConfiguration.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.");
		}
}

其他解决方案

  1. 降级springboot的版本到2.3.x(推荐)

    之前我们使用springboot2.3.12.RELEASE时,设置跨域是不能allowedOriginPatterns的,接口也是正常,可以使用maven管理pom.xml 先降级到2.3.x的版本。

  2. CorsConfiguration.javaCorsConfiguration.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加载类采用就近原则,故可以进行覆盖。

本文由作者按照 CC BY 4.0 进行授权

时间不在于你拥有多少,而在于你怎样使用

2022与2023

载入天数...载入时分秒...