你都配了 CORS,浏览器还是不让过?那到底是谁在“卡你脖子”?
🏆本文收录于《滚雪球学SpringBoot 3》:
https://blog.csdn.net/weixin_43970743/category_12795608.html,专门攻坚指数提升,本年度国内最系统+最专业+最详细(永久更新)。
本专栏致力打造最硬核 SpringBoot3 从零基础到进阶系列学习内容,🚀均为全网独家首发,打造精品专栏,专栏持续更新中…欢迎大家订阅持续学习。 如果想快速定位学习,可以看这篇【SpringBoot3教程导航帖】https://blog.csdn.net/weixin_43970743/article/details/151115907,你想学习的都被收集在内,快速投入学习!!两不误。
若还想学习更多,可直接前往《滚雪球学SpringBoot(全版本合集)》:https://blog.csdn.net/weixin_43970743/category_11599389.html,涵盖SpringBoot所有版本教学文章。
演示环境说明:
- 开发工具:IDEA 2021.3
- JDK版本: JDK 17(推荐使用 JDK 17 或更高版本,因为 Spring Boot 3.x 系列要求 Java 17,Spring Boot 3.5.4 基于 Spring Framework 6.x 和 Jakarta EE 9,它们都要求至少 JDK 17。)
- Spring Boot版本:3.5.4(于25年7月24日发布)
- Maven版本:3.8.2 (或更高)
- Gradle:(如果使用 Gradle 构建工具的话):推荐使用 Gradle 7.5 或更高版本,确保与 JDK 17 兼容。
- 操作系统:Windows 11
1) 浏览器同源策略解析:CORS 不是“后端功能”,是浏览器的安全闸门
先把一个常见误会掰正:CORS 是浏览器的安全机制。
你用 Postman / curl 调接口能 200,并不代表前端也能调通——因为它们不受浏览器同源策略约束。
MDN 对同源策略的解释很清楚:同源策略限制不同源之间的交互,跨源“读操作”通常不被允许;某些跨源请求还会触发预检(preflight)。
1.1 “同源”到底怎么判?
同源 = 协议 + 域名 + 端口都一致。
比如:
http://localhost:3000和http://localhost:8080——端口不同,不同源https://api.example.com和https://www.example.com——子域不同,不同源
1.2 什么情况下会触发 Preflight(OPTIONS)?
简单理解:当浏览器觉得你的请求“有点危险/不太普通”时,就会先发一个 OPTIONS 去问:“我能不能这么玩?”
如果预检过不了,真正的 GET/POST 根本不会发出去。
Spring Framework 文档也明确:要启用跨域请求,必须有显式 CORS 配置;如果找不到匹配配置,预检会被拒绝。
2) @CrossOrigin vs 全局 WebMvcConfigurer:一个像“贴创可贴”,一个像“装门禁”
2.1 @CrossOrigin:局部、快、但容易散
适合:
- 少数接口临时开放
- Demo/PoC
- 你明确只想放开某个 Controller 或方法
典型写法:
@RestController
@RequestMapping("/api")
@CrossOrigin(
origins = "http://localhost:3000",
allowedHeaders = "*",
methods = {RequestMethod.GET, RequestMethod.POST},
allowCredentials = "true"
)
public class FooController {
@GetMapping("/foo")
public String foo() { return "ok"; }
}
缺点(真实项目很常见):
- 配置分散到处都是,半年后你自己都不敢删🙂
- 很容易漏配:某个新接口忘了加注解,前端就炸
- 更难表达“按路径统一治理”的策略
2.2 WebMvcConfigurer#addCorsMappings:全局治理、结构清晰(推荐主力用它)
Spring MVC 的 CORS 机制会在请求映射到 handler 后检查 CORS 配置:预检请求会被直接处理,实际请求会被拦截校验并写入响应头。
全局配置示例(Spring Boot 3 / Spring MVC):
@Configuration
public class CorsWebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://localhost:3000")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.exposedHeaders("Location") // 需要前端读到的响应头
.allowCredentials(true)
.maxAge(3600);
}
}
一句很要命的提醒:
如果 allowCredentials(true),你就别再写 allowedOrigins("*") 这种“全放开”——浏览器会直接拒绝(这是 CORS 规范层面的限制,属于“你想放我也不让你放”的那种😅)。
(生产建议用明确域名列表,或 allowedOriginPatterns 做模式匹配。)
3) Spring Security 层面配置 CORS 的优先级陷阱:你以为是 MVC 配置没生效,其实是安全链先把你按住了
这是最经典的“明明我配了,为啥不行”的根源:
你在 Spring MVC 配了 CORS,但 Spring Security 过滤器链更早执行,直接把预检/跨域请求挡了。
Spring Security 官方文档强调:确保 CORS 最先被处理的最简单方式是使用 CorsFilter;并且 Spring Security 只有在存在 UrlBasedCorsConfigurationSource 时才会自动配置 CORS。
换句话说:
- 只配 WebMvcConfigurer:MVC 认识 CORS,但 Security 可能不配合
- Security 没启用 cors() 或没提供 CorsConfigurationSource:预检可能被 401/403 干掉
- 然后浏览器报 CORS 错,你还以为是“响应头没加上”……其实是你根本没走到 MVC 那一步🙂
3.1 推荐:在 SecurityFilterChain 里显式启用 CORS + 提供配置源
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.cors(cors -> {}) // ✅ 启用 CORS(交给 CorsConfigurationSource)
.csrf(csrf -> csrf.disable()) // 示例:按需开启/关闭
.authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() // ✅ 预检放行
.requestMatchers("/api/**").authenticated()
.anyRequest().permitAll()
);
return http.build();
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(List.of("http://localhost:3000"));
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
config.setAllowedHeaders(List.of("*"));
config.setAllowCredentials(true);
config.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/**", config);
return source;
}
}
这套做法对“优先级陷阱”非常有效,因为它满足了 Spring Security 文档说的关键点:
- CORS 由
CorsFilter/ Security 集成优先处理 - 存在
UrlBasedCorsConfigurationSource时,Security 才会自动配置 CORS
你会发现:同样是 CORS 配置,放在 Security 侧更“靠谱”,因为它就在请求入口的过滤器链上,能保证预检不被误伤。
4) 处理 Preflight Request(OPTIONS):别让预检死在 401/403 上
Spring Framework 文档明确:如果没有匹配的 CORS 配置,预检会被拒绝。
而在开启 Spring Security 时,预检经常死于两类问题:
4.1 典型死法 1:OPTIONS 被要求认证
浏览器发预检通常不带认证信息(或至少你不该依赖它),结果 Security 看见没登录就 401/403。
解决:显式放行 OPTIONS(上面已经示例了)。
.authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
// ...
)
4.2 典型死法 2:预检的 Allowed-Headers / Allowed-Methods 对不上
浏览器预检会带:
Access-Control-Request-MethodAccess-Control-Request-Headers
如果你的后端没允许这些 header/method,预检失败,前端就只剩一句“CORS error”(非常不友好🙂)。
建议你在开发阶段先放宽:
allowedHeaders("*")- methods 把你可能用到的都列上(尤其别忘了 OPTIONS)
上线再收紧(别一上来就“极致安全”,最后你会“极致痛苦”😂)。
一套“少踩坑”的推荐策略(我自己的偏好,供你参考🙂)
- 主力走全局配置:要么 WebMvcConfigurer,要么(更推荐)Security 侧的 CorsConfigurationSource
- 只在个别接口用 @CrossOrigin:比如临时开放、第三方回调、单独策略
- Security 一定显式启用 cors(),并提供
UrlBasedCorsConfigurationSource - 预检 OPTIONS 放行(至少对你开放跨域的路径)
- allowCredentials(true) 时,Origin 不能是 “*”(用明确域名或 pattern)
🧧福利赠与你🧧
无论你是计算机专业的学生,还是对编程有兴趣的小伙伴,都建议直接毫无顾忌的学习此专栏「滚雪球学SpringBoot」,bug菌郑重承诺,凡是学习此专栏的同学,均能获取到所需的知识和技能,全网最快速入门SpringBoot,就像滚雪球一样,越滚越大, 无边无际,指数级提升。
最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。
同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G PDF编程电子书、简历模板、技术文章Markdown文档等海量资料。
ps:本文涉及所有源代码,均已上传至Gitee:
https://gitee.com/bugjun01/SpringBoot-demo开源,供同学们一对一参考 Gitee传送门https://gitee.com/bugjun01/SpringBoot-demo,同时,原创开源不易,欢迎给个star🌟,想体验下被🌟的感jio,非常感谢❗
🫵 Who am I?
我是 bug菌:
- 热活跃于 CSDN:
https://blog.csdn.net/weixin_43970743| 掘金:https://juejin.cn/user/695333581765240| InfoQ:https://www.infoq.cn/profile/4F581734D60B28/publish| 51CTO:https://blog.51cto.com/u_15700751| 华为云:https://bbs.huaweicloud.com/community/usersnew/id_1582617489455371| 阿里云:https://developer.aliyun.com/profile/uolxikq5k3gke| 腾讯云:https://cloud.tencent.com/developer/user/10216480/articles等技术社区; - CSDN 博客之星 Top30、华为云多年度十佳博主&卓越贡献奖、掘金多年度人气作者 Top40;
- 掘金、InfoQ、51CTO 等平台签约及优质作者;
- 全网粉丝累计 30w+。
更多高质量技术内容及成长资料,可查看这个合集入口 👉 点击查看:https://bbs.csdn.net/topics/612438251 👈️
硬核技术公众号 「猿圈奇妙屋」https://bbs.csdn.net/topics/612438251 期待你的加入,一起进阶、一起打怪升级。
- End -
- 点赞
- 收藏
- 关注作者
评论(0)