最后更新:2026-10-28
适用场景:Spring Boot 3.x、Spring MVC、Spring Security 6.x、前后端分离
Postman 调接口成功,浏览器却报 CORS;Controller 里的断点一个都没进。这个组合很常见,也说明先别盯着业务方法。浏览器可能在正式 POST 前先发了一个 OPTIONS 预检请求,它已经被拦下,正式请求根本没机会到 Controller。
先在 Network 里找失败的那一条
打开浏览器开发者工具的 Network,保留日志并重试。看失败的是 OPTIONS 还是正式的 POST,记下 Request URL、Origin、Access-Control-Request-Method 和响应状态。不要只凭控制台一句“跨域错误”猜原因:后端 500、网关 502 或登录重定向也可能让响应缺少 CORS 头,浏览器最后显示的仍是跨域提示。
用命令行模拟预检,可以把浏览器界面与后端处理分开:
curl -i -X OPTIONS 'https://api.example.com/api/orders' \
-H 'Origin: https://app.example.com' \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: content-type,authorization'
把两个域名和路径换成自己的。响应应允许对应的来源、方法和请求头;只看到 HTTP 200,却没有 Access-Control-Allow-Origin,浏览器照样不会放行。Origin 包括协议、域名和端口,http://localhost:5173 与 http://localhost:3000 不是同一个来源。
只有 Spring MVC 时,把允许范围写清楚
下面是针对 /api/** 的最小配置,适用于后端确实允许该前端站点调用的情况:
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("https://app.example.com")
.allowedMethods("GET", "POST", "PUT")
.allowedHeaders("Content-Type", "Authorization");
}
}
这个配置没有自动允许 /admin/**,也不会匹配写错的来源。生产环境别为了让错误消失,直接把所有来源、所有路径都放开。确实需要浏览器携带 Cookie 时,还要评估 allowCredentials(true)、Cookie 的 SameSite / Secure 属性和 CSRF 策略;带凭据的请求不能把 allowedOrigins 设为 "*"。Spring MVC 的 CORS 文档写明了这些限制。
项目用了 Spring Security,就检查过滤器链
预检请求通常没有登录 Cookie。如果它先被鉴权逻辑按“未登录”拒掉,Controller 上即使写了 @CrossOrigin,也可能救不了这次请求。Spring Security 6.x 建议让 CORS 处理发生在鉴权之前;在已有 SecurityFilterChain 中启用它,并保留项目原有的授权规则:
http.cors(Customizer.withDefaults());
如果项目已有 Spring MVC 的 CORS 配置,且没有另外声明 CorsConfigurationSource,Security 可以使用 MVC 的配置。若有多条 SecurityFilterChain 或多个 CORS 配置源,要核对请求实际命中了哪条链。不要用关闭 Security、全局放行 OPTIONS 来掩盖配置错误,尤其不要顺手关掉 CSRF 或认证。Spring Security 6.5 的官方说明对此有专门示例。
返回 403 时,沿请求路径查
先看 OPTIONS 是由网关、Nginx 还是 Spring 应用返回的。网关自己响应预检时,后端配置再正确也不会被执行。若请求已到 Spring,检查路径是否匹配 /api/**,来源是否一字不差,方法和请求头是否被允许;再检查是否被 Security 的过滤器链拦截。
预检通过后还要看 正式请求。OPTIONS 返回 204/200 只能证明浏览器可以继续发请求,不能证明 POST 的认证、参数校验或业务逻辑没有问题。后续若是 JSON 参数绑定失败,可对照Spring Boot 接收 JSON 参数;响应格式不统一可看全局异常处理。
参考资料
Spring Framework 6.2:Spring MVC CORS
Spring Security 6.5:CORS
更新记录
2026-10-28:创建文章,补充预检复现、MVC 与 Security 分层排查。
Spring Boot 跨域预检请求 403 怎么排查
https://java.li/archives/spring-boot-cors-preflight-403
评论