添加@CrossOrigin("*")仍遇CORS跨域问题求助
你遇到的这个问题很典型——明明加了@CrossOrigin("*")注解,前端还是触发CORS拦截错误,结合你提到的服务是通过FeignClient调用下游应用的场景,核心原因大概率是实际返回给前端的响应来自下游服务,而下游未配置CORS;或者当前服务的CORS配置被拦截(比如Spring Security)导致未生效。下面给你一步步排查和解决的方案:
一、先修正前端的小细节(避免额外干扰)
你的前端代码里用了JSON.stringify(this.productModel)作为POST请求体,其实HttpClient.post会自动帮你序列化对象为JSON,并设置正确的Content-Type: application/json请求头。手动stringify反而可能导致后端@RequestBody解析失败(虽然这不是CORS的直接原因,但可能引发其他问题),建议修改为:
getPro () { return this.http.post<Product>(this.baseUrl + "/products/getPro", this.productModel); }
二、排查当前服务的CORS配置是否真正生效
1. 检查Spring Security的拦截影响
如果你的项目引入了Spring Security,它的过滤器链会在Controller之前执行,很可能覆盖@CrossOrigin的配置。需要在Security配置类中显式开启CORS支持:
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http // 优先开启CORS,再配置其他安全规则 .cors().and() .csrf().disable() // 若无需CSRF保护可关闭,根据业务场景调整 .authorizeRequests() .anyRequest().permitAll(); // 示例配置,实际按需设置权限规则 } // 配置全局CORS规则(可替代@CrossOrigin注解,更可靠) @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOrigins(Arrays.asList("*")); // 生产环境建议指定具体域名 configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); configuration.setAllowedHeaders(Arrays.asList("*")); configuration.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } }
2. 改用全局CORS配置替代注解
有时候类上的@CrossOrigin可能因为路径匹配、框架版本兼容等原因不生效,改用全局配置更稳妥。上面的corsConfigurationSource Bean会对所有请求生效,不管是否经过Feign转发。
三、处理FeignClient转发的核心问题
你的服务是通过Feign调用下游应用后,直接把下游的响应返回给前端,这时候响应头是下游服务生成的,而非当前服务添加的。针对这个场景有两种解决思路:
方案1:让下游服务配置CORS
直接在下游服务的Controller上添加@CrossOrigin("*"),或者配置全局CORS规则,这样下游返回的响应头里就会包含Access-Control-Allow-Origin,前端就能正常接收。
方案2:在当前服务手动添加CORS响应头
如果无法修改下游服务的配置,可以在当前服务的Controller中,给Feign返回的Response手动追加CORS头。比如修改你的getPro方法:
@PostMapping(value = "/getPro", consumes = {"application/json"}, produces = {"application/json"}) public ResponseEntity<?> getPro(@RequestBody Product product){ ResponseEntity<?> response = this.productService.getPro(product); // 复制原有响应头并添加CORS相关字段 HttpHeaders headers = new HttpHeaders(); headers.putAll(response.getHeaders()); headers.add("Access-Control-Allow-Origin", "*"); headers.add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); headers.add("Access-Control-Allow-Headers", "*"); return new ResponseEntity<>(response.getBody(), headers, response.getStatusCode()); }
更优雅的方式是用拦截器,在所有响应返回前统一添加CORS头:
@Component public class CorsResponseInterceptor implements HandlerInterceptor { @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { response.addHeader("Access-Control-Allow-Origin", "*"); response.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); response.addHeader("Access-Control-Allow-Headers", "*"); } }
然后在WebMvc配置中注册这个拦截器:
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Autowired private CorsResponseInterceptor corsResponseInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(corsResponseInterceptor).addPathPatterns("/**"); } }
四、验证OPTIONS预检请求
浏览器在发送复杂请求(比如带JSON body的POST)之前,会先发送一个OPTIONS预检请求确认服务器允许该操作。只要你配置了全局CORS或Spring Security开启了CORS支持,这个请求会被自动处理,无需额外配置。
按照上面的步骤排查调整,应该就能解决你的CORS问题了。
内容的提问来源于stack exchange,提问作者foufa oueslati

