Angular 14请求返回200却触发CORS源不匹配错误求助
解决Angular 14与SpringBoot间的CORS匹配问题
问题现象
- Angular 14发起GET请求后,浏览器返回200状态码但请求标红,Angular判定请求失败
- 可获取响应体,但控制台报错:
Reason: CORS header 'Access-Control-Allow-Origin' does not match - 后端SpringBoot已配置
@CrossOrigin(origins = "*")及安全配置http.cors() - Angular应用部署在Docker的Nginx容器中,Traefik v1.7配置了自定义CORS响应头
核心原因分析
- 重复CORS配置冲突:SpringBoot和Traefik同时设置
Access-Control-Allow-Origin头,导致响应中出现多个该字段,浏览器因无法识别合法来源判定失败 - Traefik头格式错误:Traefik v1.7中
customResponseHeaders的多字段分隔符应为逗号(,),而非你使用的||,这会导致CORS头解析异常 - 预检请求处理不完整:GET请求设置了
Content-Type: application/json,会触发OPTIONS预检请求,若后端或网关未正确处理该请求,也会引发CORS错误
解决方案
1. 移除重复的CORS配置
选择保留SpringBoot或Traefik其中一方的CORS配置,避免重复设置:
- 方案A:保留SpringBoot配置,移除Traefik的CORS头
注释或删除Traefik配置中的Access-Control-Allow-Origin:*部分:- "traefik.frontend.headers.customResponseHeaders=Access-Control-Allow-Methods:GET,POST,OPTIONS||Access-Control-Allow-Headers:DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range||Access-Control-Expose-Headers:Content-Length,Content-Range" - 方案B:保留Traefik配置,移除SpringBoot的CORS设置
删除控制器上的@CrossOrigin注解,并注释安全配置中的http.cors()
2. 修正Traefik的响应头格式
若选择保留Traefik的CORS配置,需将多字段分隔符改为逗号(,),正确配置如下:
- "traefik.frontend.headers.customResponseHeaders=Access-Control-Allow-Origin:*,Access-Control-Allow-Methods:GET,POST,OPTIONS,Access-Control-Allow-Headers:DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Access-Control-Expose-Headers:Content-Length,Content-Range"
3. 确保SpringBoot正确处理预检请求
若保留SpringBoot配置,建议自定义全局CORS配置以覆盖局部注解,确保OPTIONS请求被正确处理:
@Configuration public class CorsConfig { @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration config = new CorsConfiguration(); // 允许所有来源,生产环境建议指定具体域名 config.setAllowedOrigins(Collections.singletonList("*")); config.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS")); config.setAllowedHeaders(Arrays.asList("DNT", "User-Agent", "X-Requested-With", "If-Modified-Since", "Cache-Control", "Content-Type", "Range")); config.setExposedHeaders(Arrays.asList("Content-Length", "Content-Range")); // 允许携带凭证(若需要) config.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return source; } }
然后在安全配置中确保使用该配置:
@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.cors().configurationSource(corsConfigurationSource()) // 其他安全配置... .and().csrf().disable(); } }
4. 简化Angular请求头(可选)
若GET请求无需Content-Type: application/json,可移除该头,避免触发预检请求:
ifRegistred(facebookId: string): Observable<number> { console.error('function :: ifRegistred'); let url = 'https://api.app.com/ws/api/user/exist/'+facebookId; return this.http.get<number>(url).pipe( tap(memberId => { console.error('function :: ifRegistred -> success'); }), catchError((error) => { console.error('function :: ifRegistred -> failed'); this.httpError(error); return of(0); }) ); }
验证步骤
- 修改配置后重启对应服务(SpringBoot、Traefik、Nginx容器)
- 打开浏览器开发者工具,查看请求的响应头,确认仅存在一个
Access-Control-Allow-Origin字段,且值为*或对应域名 - 查看网络请求中的OPTIONS预检请求,确认其返回200状态码及正确的CORS头
内容的提问来源于stack exchange,提问作者NAD
相关产品推荐
相关产品推荐

