spring boot CORS 跨域
CORS 通俗讲解(结合图里场景:React 前端 + SpringBoot 后端)
1. 先看懂图里场景
- 前端 React:
http://localhost:5173 - SpringBoot 后端:
http://localhost:8080
协议、域名、端口任意一个不一样 → 跨域。
浏览器自带安全机制 CORS(跨域资源共享),默认阻止这种请求,控制台直接报红色 CORS 错误。
重点:跨域限制是【浏览器行为】,后端接口本身能收到请求,浏览器拦截了返回结果,不是 SpringBoot 直接拒绝!
2. SpringBoot 最简单三种解决方案(从简单到规范)
方式 1:单个 Controller 快速开启(最简单,测试用)
直接在控制器类上加注解
java
运行
@RestController @RequestMapping("/api/companies") @CrossOrigin(origins = "http://localhost:5173") // 允许前端地址跨域 public class CompanyController { @GetMapping public List<CompanyDTO> getAll(){ //业务代码 } }
@CrossOrigin 写在类上:当前 Controller 全部接口允许跨域;
origins = "*"代表允许所有前端地址(生产环境不推荐,不安全,仅本地测试)
java
运行
@CrossOrigin(origins = "*")
方式 2:全局配置(项目正式推荐,所有接口统一生效)
新建一个配置类,一次性全局开启跨域,不用每个 Controller 加注解
java
运行
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("/**") // 匹配后端所有接口 .allowedOrigins("http://localhost:5173") //允许的前端域名 .allowedMethods("GET","POST","PUT","DELETE") //允许请求方式 .allowCredentials(false); } }
3. 完整流程演示(发生了什么)
- 前端
localhost:5173axios 请求后端localhost:8080/api/companies - 浏览器识别:地址不一样 = 跨域
- 浏览器自动先发 OPTIONS 预检请求询问后端:允不允许这个前端访问你?
- 如果后端配置了 CORS,响应头带上
Access-Control-Allow-Origin - 浏览器看到合法响应头 → 放行,正式发送 GET/POST 请求
- 没有配置 CORS → 浏览器直接拦截,报图中的 CORS Policy 错误
4. 重要避坑知识点
- ❌ 不要以为后端能收到请求 = 没有跨域
后端代码正常执行,但是浏览器不给前端接收返回数据。
*不能和allowCredentials=true(携带 Cookie)同时使用;- 生产环境不要写
*,指定真实前端域名,防止恶意网站调用你的接口。 - CORS 只限制浏览器 AJAX/fetch 请求。Postman、后端之间调用接口不受跨域约束!
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
这是 全局统一配置跨域方案,不需要在每个 Controller 写
@CrossOrigin,企业项目最常用方式。java
运行
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("https://domain2.com") .allowedMethods("PUT", "DELETE") .allowedHeaders("header1", "header2", "header3") .exposedHeaders("header1", "header2") .allowCredentials(true) .maxAge(3600); } }
每一条方法含义拆解
-
registry.addMapping("/api/**")匹配路径规则:只对后端/api/开头所有接口 启用跨域规则。如果你写/**= 后端全部接口生效。 -
.allowedOrigins("https://domain2.com")允许哪个前端域名跨域访问后端;👉 只允许https://domain2.com,其他前端域名一律拦截。
测试可以写"*",生产绝对不推荐。
-
.allowedMethods("PUT", "DELETE")允许哪些 HTTP 请求方式跨域。这里仅开放 PUT、DELETE;GET/POST 都会被阻止!一般项目完整写法:"GET","POST","PUT","DELETE" -
.allowedHeaders("header1", "header2", "header3")允许前端请求携带哪些自定义请求头。前端如果传了不在列表内的 header,浏览器直接跨域报错。 -
.exposedHeaders("header1", "header2")【容易混淆重点】默认情况下:前端 JS 拿不到后端返回的自定义响应头。配置这里,代表告诉浏览器:允许前端读取这几个返回头。 -
.allowCredentials(true)允许跨域请求携带 Cookie、Session 凭证。⚠️ 重要冲突规则:开启true之后,allowedOrigins不能写*通配符,必须指定具体域名! -
.maxAge(3600)浏览器预检 OPTIONS 请求缓存时长,单位秒。3600 = 1 小时:1 小时之内,浏览器不用重复发送 OPTIONS 预检询问后端,优化性能。
和 @CrossOrigin 注解对比
@CrossOrigin:局部,作用在单个 Controller / 接口,适合临时测试WebMvcConfigurer + addCorsMappings:全局统一管理所有接口一套规则,便于维护,正式项目首选。
适配你之前项目的实战改造示例
前端地址:
http://localhost:5173,后端接口 /api/**java
运行
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("http://localhost:5173") .allowedMethods("GET","POST","PUT","DELETE") .allowCredentials(false) .maxAge(3600); } }
补充一个坑
如果你项目同时使用 Spring Security,单纯这个配置会失效!
Security 有自己的 CORS 校验,需要额外在 Security 配置中开启 cors 支持。
一句话总结幻灯片内容
实现
WebMvcConfigurer接口,重写addCorsMappings,可以集中定义一套细粒度跨域策略:限制哪些接口、哪个前端域名、哪些请求方式、请求头允许跨域访问。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
先说核心原因(为什么 WebMvc 跨域配置会失效)
Spring Security 的过滤器链 执行顺序早于 SpringMVC 的 CORS 处理
请求先进 Security 过滤器 → Security 先校验跨域,如果没放行,直接拒绝请求,根本不会走到
WebMvcConfigurer#addCorsMappings。简单流程:
浏览器 OPTIONS 预检请求 → Security 过滤器(优先执行)
→ Security 默认没有开启 CORS 支持 → 直接 403 拒绝
→ MVC 全局跨域代码永远得不到执行
解决方案:两处任选其一,推荐方案 2(统一管理)1)Security 内部启用 Cors,并且复用 MVC 的跨域配置2)Security 内部直接定义 Cors 配置(不依赖 WebMvc)
二、标准完整配置(你现有代码基础改造)
你已经有这个 MVC 跨域配置:
java
运行
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("http://localhost:5173") .allowedMethods("GET","POST","PUT","DELETE") .allowCredentials(false) .maxAge(3600); } }
关键:SpringSecurity 配置里开启 .cors()
java
运行
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.SecurityFilterChain; @Configuration public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // ✅ 最重要一行!启用CORS,自动读取上面WebMvc的跨域规则 .cors() .and() .csrf().disable() //前后端分离项目一般关闭csrf .authorizeHttpRequests(auth -> auth .requestMatchers("/api/public/**").permitAll() .anyRequest().authenticated() ); return http.build(); } }
加上
.cors() 之后,Security 会自动寻找容器中 WebMvcConfigurer 的跨域规则,两者共用一套配置,不用重复写代码。三、备选方案:完全在 Security 中硬编码 CORS(不依赖 WebMvc)
如果你不想使用 WebMvc 的配置,可以手动提供一个
CorsConfigurationSource Bean:java
运行
@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .cors(cors -> cors.configurationSource(corsConfigurationSource())) .csrf().disable() .authorizeHttpRequests(auth -> auth.anyRequest().permitAll()); return http.build(); } // 单独定义跨域规则 @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration config = new CorsConfiguration(); config.setAllowedOrigins(List.of("http://localhost:5173")); config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE")); config.setMaxAge(3600L); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/api/**", config); return source; }
四、高频踩坑清单
- ❌ 只写 WebMvcConfigurer,Security 不加
.cors()→ 跨域直接失效 - ❌
allowCredentials(true)+allowedOrigins("*")浏览器规范不允许,启动不报错,前端依然跨域失败!必须写明确域名 - ❌ 同时多处定义跨域(@CrossOrigin + WebMvc + Security)容易规则冲突,建议统一一套
- OPTIONS 预检请求被 Security 拦截:开启
.cors()之后框架会自动放行 OPTIONS,不需要手动放行 OPTIONS 接口
五、最简总结
SpringSecurity 过滤器执行优先级高于 SpringMVC,必须在 Security 中显式开启 .cors ();开启后自动复用 WebMvcConfigurer 的跨域规则,一套配置全局生效。
如果你需要,我可以给你一份可以直接复制、前后端分离(React5173 + SpringBoot8080 + Security)完整可运行样板代码。

浙公网安备 33010602011771号