网站首页 > 文章精选 正文
"前端调用接口直接报红,
Access-Control-Allow-Origin是什么鬼?"
"明明Postman能调通,浏览器死活提示跨域!"
"配置了CorsFilter为什么还有问题?"
每个全栈开发都躲不过的经典天坑——跨域问题(CORS)。本文从HTTP协议原理出发,手撕Spring Boot中3种根治方案,包含Spring Security特殊场景处理、生产环境安全指南,以及源码层执行顺序解析,拒绝无效配置!
一、跨域本质:3分钟搞懂为什么浏览器要拦你?
划重点:跨域是浏览器的安全策略,与服务端无关!
- 触发条件(同时满足):
- 协议、域名、端口任意一个不同
- 请求包含自定义Header(如Token)
- 使用PUT、DELETE等非简单请求
- 底层原理:
- bash
# 真实场景中的CORS流程
1. 浏览器发送OPTIONS预检请求 →
2. 服务端返回允许的Origin/Methods/Headers →
3. 浏览器放行真实请求
关键点:若预检请求未通过,真实请求根本不会发出!
二、Spring Boot三大解决方案(附避坑指南)
方案1:@CrossOrigin注解 - 适合临时调试
java
@RestController
public class UserController {
// 单个接口允许跨域(默认允许所有来源)
@CrossOrigin(origins = "http://localhost:8080")
@GetMapping("/api/user")
public User getUser() {
return new User("James", 30);
}
// 允许携带Cookie(需前端配合withCredentials)
@CrossOrigin(origins = "*", allowCredentials = "true") // 生产环境慎用!
@PostMapping("/api/login")
public void login() {}
}
坑点:
- 类级别注解会被方法级别覆盖
- 无法设置exposedHeaders(如暴露Authorization头)
方案2:全局配置WebMvcConfigurer- 推荐标准方案
java
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 拦截所有路径
.allowedOrigins("https://your-domain.com") // 生产环境禁用*
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.exposedHeaders("Authorization") // 暴露自定义Header
.allowCredentials(true) // 允许Cookie
.maxAge(3600); // 1小时内不需要预检
}
}
避坑指南:
- 若同时存在Filter方案,此配置可能失效(执行顺序问题)
- allowedOrigins不能同时设置*和allowCredentials=true(浏览器会阻止)
方案3:自定义CorsFilter - 终极控制权
java
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("https://your-domain.com");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.addExposedHeader("Authorization");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
适用场景:
- 需要精细控制跨域逻辑(如动态Origin)
- 整合第三方Filter导致优先级冲突时
三、Spring Security特殊处理:为什么配置了还是报错?
致命陷阱:Spring Security过滤器链优先于CorsFilter!
java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors() // 必须显式启用Spring Security的CORS支持!
.and()
// 其他安全配置...
.csrf().disable();
}
// 关键!需声明CorsConfigurationSource
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.applyPermitDefaultValues(); // 根据需求定制
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
}
原理:Spring Security的CorsFilter会覆盖自定义配置,必须通过cors().configurationSource()注入!
四、生产环境安全指南(血泪教训)
- 严禁使用allowedOrigins("*")
- 推荐动态读取白名单:
- java
- 复制
- 下载
- @Value("${cors.allowed-origins}") private String[] allowedOrigins;
- 限制HTTP方法:
- java
.allowedMethods("GET", "POST") // 按需开放
- 严格设置allowedHeaders:
- java
.allowedHeaders("Content-Type", "Authorization") // 拒绝无用Header
- 启用CSRF保护(除非是纯API服务)
五、终极调试技巧
当配置无效时:
- 浏览器Network面板:查看Response Headers是否包含CORS头
- 服务端日志:添加日志拦截器打印请求头
- 源码断点:
- CorsInterceptor(全局配置)
- CorsFilter(过滤器方案)
- DefaultCorsProcessor(处理逻辑)
结语
跨域问题本质是协议规则与框架执行顺序的博弈。掌握这3种方案+安全规则,能解决99%的CORS报错。点赞收藏,下次前端再喊“接口跨域了”,把这篇文章甩给他!
猜你喜欢
- 2025-05-08 100%开源免费的低代码/可视化数据分析、数据展示平台
- 2025-05-08 永久免费内网穿透很简单,一看就明白
- 2025-05-08 Odoo 用户菜单架构解析及创建和管理实战
- 2025-05-08 关于编码的那些事 - URL 编码(编码url是什么意思)
- 2025-05-08 20 个让人惊叹的 JavaScript 单行代码技巧,效率瞬间提升
- 2025-05-08 如何使用java.net.URLConnection发起和处理HTTP请求
- 2025-05-08 崩溃!代码总掉链子?6 个 JavaScript 技巧助你稳操胜券
- 2025-05-08 抓狂!代码总出错?5 个 JavaScript 技巧助你逆风翻盘
- 2025-05-08 前端性能拉胯?这 8 个 JavaScript 技巧让你的代码飞起来!
- 2025-05-08 崩溃!页面卡顿总翻车?6 个 JavaScript 技巧教你逆风翻盘
- 最近发表
-
- 100%开源免费的低代码/可视化数据分析、数据展示平台
- Spring Boot跨域问题终极解决方案:3种方法根治CORS报错
- 永久免费内网穿透很简单,一看就明白
- Odoo 用户菜单架构解析及创建和管理实战
- 关于编码的那些事 - URL 编码(编码url是什么意思)
- 20 个让人惊叹的 JavaScript 单行代码技巧,效率瞬间提升
- 如何使用java.net.URLConnection发起和处理HTTP请求
- 崩溃!代码总掉链子?6 个 JavaScript 技巧助你稳操胜券
- 抓狂!代码总出错?5 个 JavaScript 技巧助你逆风翻盘
- 前端性能拉胯?这 8 个 JavaScript 技巧让你的代码飞起来!
- 标签列表
-
- newcoder (56)
- 字符串的长度是指 (45)
- drawcontours()参数说明 (60)
- unsignedshortint (59)
- postman并发请求 (47)
- python列表删除 (50)
- 左程云什么水平 (56)
- 计算机网络的拓扑结构是指() (45)
- 稳压管的稳压区是工作在什么区 (45)
- 编程题 (64)
- postgresql默认端口 (66)
- 数据库的概念模型独立于 (48)
- 产生系统死锁的原因可能是由于 (51)
- 数据库中只存放视图的 (62)
- 在vi中退出不保存的命令是 (53)
- 哪个命令可以将普通用户转换成超级用户 (49)
- noscript标签的作用 (48)
- 联合利华网申 (49)
- swagger和postman (46)
- 结构化程序设计主要强调 (53)
- 172.1 (57)
- apipostwebsocket (47)
- 唯品会后台 (61)
- 简历助手 (56)
- offshow (61)