Spring Boot 跨域问题核心在于预防预检失败而非捕获异常,需确保 OPTIONS 请求放行、CORS 响应头正确返回、配置层级合理(推荐 Security 统一管理),并严格匹配请求头与方法。

Spring Boot 中处理跨域请求异常,核心不是“捕获异常”,而是提前预防预检失败、避免真实请求被拦截。浏览器报的 CORS 错误(比如“No 'Access-Control-Allow-Origin' header”)通常不是后端抛出的 RuntimeException,而是响应中缺失必要头导致的策略拒绝。真正要解决的,是让 OPTIONS 预检顺利通过、让带凭证或自定义头的真实请求不被中间件拦住。
确认是否真进了 Spring Boot 应用层
很多所谓“跨域异常”其实请求根本没到你的 Controller——它被 Spring Security、自定义拦截器、甚至网关/Nginx 拦截了。先验证这点:
- 打开浏览器 Network 面板,看失败请求前是否有 OPTIONS 请求;如果有,点开它看响应状态码和响应头(尤其 Access-Control-Allow-Origin 是否存在)
- 在后端加一个最简过滤器(如 `OncePerRequestFilter`),在 `doFilterInternal` 开头打日志,确认 OPTIONS 请求是否进入应用。如果没日志,问题在网关或容器层
- 用 curl 手动发预检请求:
curl -i -X OPTIONS http://localhost:8080/api/user -H "Origin: http://localhost:3000" -H "Access-Control-Request-Method: GET"
观察返回状态和头
重点防住 OPTIONS 被登录/权限拦截器拦掉
这是最常见根源:JWT 或 Session 登录拦截器对所有请求一视同仁,连无 token 的 OPTIONS 也返回 401/403。浏览器收到非 2xx 的预检响应,直接终止后续请求,还报“CORS 头缺失”——其实是因为 401 响应里你没手动写 CORS 头。
- 在拦截器 `preHandle` 中,明确跳过 OPTIONS 方法:
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { return true; } - 如果用了 Spring Security,确保 `http.cors()` 已启用,并把 `CorsConfigurationSource` 配置在安全链之前:
http.cors(withDefaults()).csrf(...).authorizeHttpRequests(...) - 避免在拦截器里对 OPTIONS 返回 401 响应体——它不需要业务逻辑,放行即可
选对 CORS 配置层级,避免被覆盖
多种配置共存时容易互相覆盖。优先级从高到低一般是:Filter > Security > @CrossOrigin > WebMvcConfigurer。生产建议统一收口:
- 开发阶段快速验证:直接在 Controller 类上加
@CrossOrigin(origins = "http://localhost:3000") - 项目稳定后,用全局配置(实现
WebMvcConfigurer)并限定路径,如registry.addMapping("/api/**"),避免开放整个/** - 若用 Spring Security,不要同时配 WebMvcConfigurer 和 Security 的 cors(),否则后者可能失效;推荐只用 Security 的 cors 配置,更可靠
- 需要动态源(如多租户)时,用
CorsConfiguration.setAllowedOriginPatterns替代固定 origins
响应头必须匹配请求细节
哪怕配置了 CORS,如果请求头或方法不匹配,预检仍会失败:
- 前端发了
Authorization头 → 后端配置必须包含.allowedHeaders("Authorization")或"*"(注意:allowCredentials=true 时不能用 "*") - 前端用 POST + JSON → Content-Type 是
application/json,属于非简单请求,必然触发预检;确保后端允许该 method 和 header - 若需携带 cookie 或 token,必须同时设
.allowCredentials(true)且前端 fetch 加credentials: 'include',此时allowedOrigins不能为"*",必须写具体域名


















