Spring Boot对接Angular时控制器级@CrossOrigin配置仍出现CORS报错
调用Spring Boot 2.6.4版本的Web服务接口时触发CORS跨域错误,错误截图如下:
前端使用Angular 13版本,原请求代码如下:
let headers = new HttpHeaders({ 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'Content-Type', 'Access-Control-Allow-Methods': 'GET,POST,OPTIONS,DELETE,PUT' }); let options = { headers: headers }; this.http.get<any>("http://localhost:8080/country/available", options).subscribe(data => { console.log(data); });
已在控制器层级添加@CrossOrigin注解配置跨域规则,后端控制器代码如下:
@RestController @CrossOrigin(origins = "*", maxAge = 3600) @RequestMapping("country") public final class CountryController { private final transient CountryService countryService; @Autowired public CountryController(final CountryService countryService) { this.countryService = countryService; } @GetMapping("/available") public List<Country> getAvailableCountries() { return countryService.getAvailableCountries(); } }
上述配置完成后跨域问题仍存在,以下是排查修复方案。
首先修正前端请求的错误配置
Access-Control-Allow-*系列头是后端返回给浏览器的响应头,绝对不能放在前端请求头里携带。手动加这几个头不仅无效,还会触发浏览器额外的预检校验,直接导致跨域失败。把这几个CORS相关头从前端headers里删掉,只保留业务需要的头即可,修正后代码:let headers = new HttpHeaders({ 'Content-Type': 'application/json' }); let options = { headers: headers }; this.http.get<any>("http://localhost:8080/country/available", options).subscribe(data => { console.log(data); });替换零散的控制器跨域注解,配置全局CORS规则
Spring Boot 2.6版本中,如果项目存在自定义拦截器、过滤器或者引入了Spring Security,控制器上的@CrossOrigin注解优先级很低,会在跨域头写入前就被拦截逻辑截断,导致配置不生效。直接新增全局CORS配置类覆盖所有接口,稳定性更高:import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); } }注意:Spring Boot 2.4及以上版本,不要同时配置
allowedOrigins("*")和allowCredentials(true),会触发配置报错,通配符匹配域名请用allowedOriginPatterns("*")如果项目引入了Spring Security,额外开启CORS放行
若项目使用Spring Security做权限控制,需要在安全过滤器链中显式开启CORS支持,否则预检的OPTIONS请求会被安全逻辑直接拦截返回403,配置示例:import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.SecurityFilterChain; import org.springframework.context.annotation.Bean; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .cors().and() .csrf().disable() // 下方按你实际的业务权限规则配置即可 .authorizeHttpRequests(auth -> auth .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() .anyRequest().authenticated() ); return http.build(); }最终验证
重启后端服务,清空浏览器缓存后重新发起请求,打开浏览器开发者工具的Network面板,查看接口对应的OPTIONS预检请求响应头中是否存在Access-Control-Allow-Origin字段,字段值匹配当前前端服务地址即代表配置生效。
内容的提问来源于stack exchange,提问作者Hyphen

