CORS 全局配置
为什么需要 CORS
浏览器有同源策略:页面所在源(协议 + 域名 + 端口)与请求目标不同源时,响应会被浏览器拦截。前后端分离开发中,前端跑在 http://localhost:5173、后端跑在 http://localhost:8080,二者不同源,直接请求就会触发跨域问题。CORS(跨源资源共享)由服务端通过响应头声明「允许哪些来源访问」,浏览器据此放行。
简单请求与预检
- 简单请求(如不带自定义头的 GET/POST 表单请求):浏览器直接带
Origin头发送,服务端返回Access-Control-Allow-Origin即可; - 复杂请求(携带自定义头、
application/json的 PUT/DELETE 等):浏览器先发一个OPTIONS预检请求,确认许可后才发真实请求。
方式一:@CrossOrigin 注解
局部控制用注解,加在方法或类上(方法级优先于类级):
@CrossOrigin(origins = "https://example.com")
@RestController
public class UserController {
// ...
}
不带参数的 @CrossOrigin 允许所有来源,开发期方便但生产慎用。本地联调时常写成 origins = "http://localhost:5173"。
方式二:全局 WebMvcConfigurer(推荐)
跨域规则统一收敛到一处,通过 WebMvcConfigurer 配置:
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**") // 这些路径参与 CORS
.allowedOrigins("https://example.com") // 允许的来源(生产不要写 *)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*") // 允许的请求头
.allowCredentials(true) // 允许携带 Cookie
.maxAge(3600); // 预检结果缓存 1 小时
}
}
要点
allowCredentials(true)与allowedOrigins("*")不能同时用,浏览器会拒绝;需要把来源写具体。- 来源是动态或想用通配子域时,用
allowedOriginPatterns("https://*.example.com")(该 API 自 Spring 5.3 提供,4.x 沿用,具体以官方文档为准)。 - 前端要读取自定义响应头时,用
exposedHeaders暴露。 - 校验失败会返回 403,浏览器控制台会提示具体被拒原因,按提示调整规则即可。
验证
# 观察响应头是否含 Access-Control-Allow-Origin
curl -i -H "Origin: https://example.com" http://localhost:8080/api/users
# 手动模拟预检
curl -i -X OPTIONS -H "Origin: https://example.com" \
-H "Access-Control-Request-Method: POST" \
http://localhost:8080/api/users
小结
跨域是「服务端许可 + 浏览器拦截」的机制。单体后端用 WebMvcConfigurer 全局配置最省心;若前端请求先经过 Nginx/网关转发,通常由网关层统一处理 CORS,后端保持默认即可,两者同时配置可能造成响应头重复。