当前位置: 首页 > news >正文

SpringBoot实战:三种主流CORS跨域配置方案详解与选型

1. 为什么我们需要CORS跨域解决方案

第一次遇到CORS报错的时候,我正对接一个前后端分离项目。前端同事信誓旦旦说接口调不通,我这边日志明明显示请求已经处理成功了。打开浏览器控制台,那个经典的红色报错赫然在目:"Access to XMLHttpRequest at 'http://api.example.com' from origin 'http://localhost:3000' has been blocked by CORS policy..." 这才意识到遇到了传说中的跨域问题。

同源策略就像小区的门禁系统。假设你住在A小区(前端域名),想去B小区(后端接口)拜访朋友。如果两个小区同属一个物业(同源),门卫直接放行;如果是不同物业(跨域),门卫就会盘查访问权限。CORS就是B小区物业给你开的访客通行证,告诉门卫:"这位访客我认识,放行吧!"

现代Web开发中,跨域场景无处不在:

  • 开发阶段:前端localhost:3000调用后端localhost:8080
  • 生产环境:前端www.example.com调用api.example.com
  • 微服务架构:网关gateway.example.com路由到各业务服务

2. 注解方案:@CrossOrigin快速上手

2.1 单方法级配置

刚接触SpringBoot时,我最喜欢用@CrossOrigin注解。就像给控制器方法贴便利贴一样简单:

@RestController @RequestMapping("/api") public class UserController { @CrossOrigin @GetMapping("/users") public List<User> listUsers() { // 返回用户列表 } }

这个注解默认允许所有来源(origins = "*"),支持GET、HEAD、POST方法。实测在SpringBoot 2.5+环境下,只需要这行代码就能让前端顺利拿到数据。

2.2 类级别与全局配置

随着项目扩大,我给每个方法都加注解实在太麻烦。这时候可以升级用法:

@CrossOrigin(origins = "https://myfrontend.com", maxAge = 3600, allowedHeaders = "*") @RestController @RequestMapping("/api") public class ProductController { // 所有方法都继承跨域配置 }

更聪明的做法是创建一个基础控制器:

@CrossOrigin public class BaseController {} @RestController @RequestMapping("/order") public class OrderController extends BaseController { // 自动获得跨域支持 }

注意:继承方式在Spring 5.3之后更推荐用@ControllerAdvice实现,避免类继承的强耦合。

3. 全局配置:WebMvcConfigurer方案

3.1 基础配置模板

当项目有几十个控制器时,我转向了全局配置方案。新建一个配置类:

@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("https://production.com", "http://localhost:3000") .allowedMethods("GET", "POST", "PUT") .allowCredentials(true) .maxAge(1800); } }

这个配置实现了:

  • 只对/api开头的接口启用CORS
  • 允许生产环境和本地开发环境跨域访问
  • 开放三种HTTP方法
  • 支持携带Cookie(前端需要配合withCredentials)
  • 预检请求缓存30分钟

3.2 多环境差异化配置

在实际项目中,我常用Spring Profile实现环境隔离:

@Profile("dev") @Configuration public class DevCorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**").allowedOrigins("*"); } } @Profile("prod") @Configuration public class ProdCorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("https://official.website"); } }

开发环境放开所有跨域限制,生产环境则严格限定可信域名。通过spring.profiles.active=dev切换配置。

4. 过滤器方案:最灵活的CORS控制

4.1 基础过滤器实现

当项目需要与老旧系统集成时,Filter方案往往最能打。这是我常用的模板:

@Component public class CustomCorsFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) res; response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization, content-type"); if ("OPTIONS".equalsIgnoreCase(((HttpServletRequest) req).getMethod())) { response.setStatus(HttpServletResponse.SC_OK); } else { chain.doFilter(req, res); } } }

这个实现特点:

  • 处理OPTIONS预检请求直接返回200
  • 允许所有来源的简单请求(生产环境应替换为具体域名)
  • 设置1小时预检缓存
  • 支持常见请求头和四种HTTP方法

4.2 动态域名白名单

在SAAS系统中,我遇到过需要动态允许租户域名的需求。改良后的过滤器:

public class DynamicCorsFilter implements Filter { @Autowired private TenantConfigService configService; @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; String origin = request.getHeader("Origin"); if (configService.isAllowedOrigin(origin)) { response.setHeader("Access-Control-Allow-Origin", origin); response.setHeader("Access-Control-Allow-Credentials", "true"); } // 其他配置... } }

通过查询数据库或Redis中的租户配置,实现动态域名校验。这种方案在多租户系统中特别实用。

5. 方案对比与选型指南

5.1 特性对比表

特性@CrossOriginWebMvcConfigurerFilter
配置粒度方法/类级别全局/路径级别全局
动态域名支持
支持Spring版本4.2+所有版本所有版本
处理OPTIONS请求自动自动需手动处理
与Spring Security兼容性中等良好最佳

5.2 选型建议

根据我踩坑经验,推荐这些场景选择:

选择@CrossOrigin当:

  • 快速原型开发
  • 只有少量接口需要跨域
  • 项目使用最新Spring版本

选择WebMvcConfigurer当:

  • 需要统一管理跨域规则
  • 项目已有WebMvc配置类
  • 需要路径模式匹配

选择Filter当:

  • 需要动态域名控制
  • 项目使用老旧Spring版本
  • 与Spring Security深度集成
  • 需要处理特殊Header逻辑

在微服务网关层,我通常采用Filter方案,因为需要处理复杂的跨域场景。而单体应用中使用WebMvcConfigurer更简洁。

http://www.jsqmd.com/news/893947/

相关文章:

  • IMXRT开发板SWO跟踪配置与调试指南
  • 保姆级教程:手把手教你安装配置Ultimaker Cura 4.8中文版(Win系统)
  • 别再乱焊了!HC-SR501人体感应模块的光敏电阻,实测告诉你到底该用多大的(附计算方法和串联技巧)
  • 【PFJSP问题】基于自适应双种群协同鸡群算法ADPCCSO求解置换流水车间调度问题PFSP附Matlab代码
  • 2026乐山临江鳝丝TOP5门店排行:乐山跷脚牛肉店有哪些、乐山跷脚牛肉排行前三、乐山跷脚牛肉更正宗、乐山跷脚牛肉哪家好选择指南 - 优质品牌商家
  • A51宏汇编器预定义宏详解与应用技巧
  • 别再傻傻重启Word了!Windows 11/10字体安装后立即生效的正确姿势
  • 从“富足的一生”到代码人生:技术人的精神富足与价值重构
  • 【鲁棒】分布式港口-哈密顿系统(Port–Hamiltonian)鲁棒调控的李雅普诺夫方法附Matlab代码
  • 【2026白皮书】嵌入式IoT模组市场全景与选型指南:5G RedCap/端侧AI/NTN深度解析
  • 订单状态机别写散:我在 Rust CRM 里把 6 个状态收进领域模型
  • 科普|论文查重为什么能免费?书匠策AI这个平台到底什么来头?
  • SkiaSharp实战:5分钟为你的C# WinForm应用添加一个“可移动的小球”
  • 找片头AE模版不用愁!12个优质素材平台汇总
  • 扩散模型驱动3D生成:从2D先验到3D空间扩散的技术演进
  • 2026年河北滤筒除尘器厂家实力厂商选择标准深度剖析 - 2026年企业资讯
  • 别再像我一样踩坑!用PSIM和Multisim手把手教你推导Buck电路的正确传递函数
  • 别再死记硬背了!用Python手把手教你实现匈牙利算法,搞定任务分配难题
  • Python数据可视化实战
  • 基于mlp的神经网络的红酒品质回归预测
  • 27考研311教育学历年真题PDF
  • 趣味智能陪伴!基于魔珐星云的宠物专属数字助手
  • 臺灣大學校總區無車化執行方案與推動時程整體規劃案(繁) 2025
  • 别再为高维数据发愁了!用Python手把手教你实现粗糙集属性约简(附完整代码)
  • ubuntu下stlink(v1/v2/v3)实现GD32下载程序
  • 从美术资源到可动角色:聊聊Unity中序列帧动画的性能优化与最佳实践
  • 告别龟速!实测FastCopy 3.92在Windows 11上拷贝百万小文件,速度提升10倍不止
  • 2026年4月成都火锅品牌口碑推荐,烧菜火锅/特色美食/美食/社区火锅/火锅,成都火锅品牌找哪家 - 品牌推荐师
  • 告别调参玄学:用Python手把手实现L1-ball投影,给你的模型加个‘稀疏’开关
  • 2026年5月江夏地区高亮LED大灯专业服务对接与品牌深度解析 - 2026年企业资讯