网站首页 > 技术文章 正文
"明明接口测试工具能调通,前端调用就报CORS错误!"
"跨域配置加了一堆注解,为什么生产环境突然失效?"
"用了Spring Security后跨域配置全崩了?"
作为全栈开发的必经之痛,跨域问题看似简单实则暗藏杀机。本文将用6种段位解决方案 + 3个真实翻车案例,带你彻底终结Spring Boot跨域难题!
一、跨域本质三句话
- 浏览器安全策略:同源策略(Same-Origin Policy)的主动防御
- 触发条件:协议/域名/端口任一不同即跨域
- 解决方案核心:服务端返回正确的CORS响应头
二、青铜到王者:6种解决方案段位进阶
青铜段位:@CrossOrigin注解(适合新手尝鲜)
java
@RestController
@CrossOrigin(origins = "http://localhost:8080",
allowedHeaders = "*",
methods = {RequestMethod.GET, RequestMethod.POST})
public class UserController {
// 仅对当前Controller生效
}
致命缺陷:
- 每个Controller都要重复配置
- 不支持携带Cookie(credentials问题)
- 无法处理OPTIONS预检请求的缓存
白银段位:全局CORS配置(推荐常规使用)
java
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*") // 生产环境建议指定具体域名
.allowedMethods("*")
.allowedHeaders("*")
.exposedHeaders("Authorization") // 暴露自定义Header
.allowCredentials(true) // 允许携带Cookie
.maxAge(3600); // 预检请求缓存时间
}
}
避坑指南:
- allowCredentials(true)时,allowedOrigins不能为*,必须指定具体域名
- 若同时使用Spring Security,需配合@EnableWebSecurity配置(下文详解)
黄金段位:自定义过滤器(应对特殊场景)
java
@Component
public class CorsFilter 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", "http://your-frontend.com");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
response.setHeader("Access-Control-Allow-Credentials", "true");
if ("OPTIONS".equalsIgnoreCase(((HttpServletRequest) req).getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
}
适用场景:
- 需要动态控制跨域策略(如多租户系统)
- 处理特殊Header要求(如自定义签名头)
铂金段位:整合Spring Security(高危操作区)
java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors() // 启用Spring Security的CORS支持
.and()
// 必须禁用CSRF否则会与CORS冲突
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated();
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://trusted-domain.com"));
configuration.setAllowedMethods(Arrays.asList("*"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
血泪教训:
- 同时存在WebMvcConfigurer和Security配置时,以Security配置为准
- 必须显式调用.cors()并配置CorsConfigurationSource
- 使用OAuth2等鉴权方案时,要注意Filter顺序
钻石段位:网关层统一处理(微服务架构推荐)
yaml
# 以Spring Cloud Gateway为例
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowed-origins: "https://*.your-domain.com"
allowed-methods: "*"
allowed-headers: "*"
allow-credentials: true
max-age: 1800
架构优势:
- 统一管控所有微服务的跨域策略
- 避免每个服务重复配置
- 支持动态路由更新
王者段位:Nginx反向代理(终极解决方案)
nginx
server {
listen 80;
server_name api.your-domain.com;
location / {
proxy_pass http://spring-boot-app:8080;
# 关键CORS配置
add_header 'Access-Control-Allow-Origin' $http_origin always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
if ($request_method = 'OPTIONS') {
return 204;
}
}
}
降维打击优势:
- 完全解耦业务代码
- 支持复杂跨域策略(如多域名动态匹配)
- 性能损耗最低
三、三大经典翻车现场复盘
翻车1:配置了allowCredentials却报错"Credentials not supported"
原因:
- 响应头Access-Control-Allow-Origin设置为*
- 浏览器安全策略禁止credentials与通配符共存
解决方案:
- 明确指定allowedOrigins为具体域名列表
- 前端axios等库需要设置withCredentials: true
翻车2:POST请求变成OPTIONS请求后404
原因:
- 未正确处理预检请求(OPTIONS方法)
- Spring Security等组件拦截了OPTIONS请求
解决方案:
- 确保服务端处理OPTIONS请求(全局配置或过滤器)
- 在Security配置中放行OPTIONS请求:
- java
- 复制
- 下载
- .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
翻车3:本地开发正常,上线后跨域失效
根本原因:
- 生产环境Nginx未正确传递Origin头
- 网关层缓存了旧的CORS配置
排查步骤:
- 检查浏览器Network面板实际响应头
- 使用curl命令测试:
bash
curl -H "Origin: http://your-domain.com" -I https://api.your-domain.com
- 确认Nginx配置中的add_header指令位置正确
四、最佳实践清单
- 开发环境:使用全局CORS配置+allowedOrigins("*")快速验证
- 生产环境:
- 网关/Nginx层精确控制允许的域名
- 禁用allowedOrigins("*")和allowedHeaders("*")
- 安全加固:
- 限制exposedHeaders仅暴露必要Header
- 对Access-Control-Max-Age设置合理缓存时间
- 鉴权体系:
- 携带Cookie时确保SameSite属性配置
- JWT等方案要处理Authorization头暴露
五、终极验证大法
在Chrome开发者工具中检查响应头是否包含:
http
Access-Control-Allow-Origin: [正确域名]
Access-Control-Allow-Credentials: true # 如需携带凭证
Vary: Origin # 防止CDN缓存错误策略
结语
跨域不是bug,而是浏览器守护你的安全防线。点赞收藏本文,下次遇到CORS问题时,对照这个“生存手册”逐级排查,从此告别熬夜抓狂!
讨论区开放:你遇过最奇葩的跨域问题是什么? 欢迎留言,点
猜你喜欢
- 2025-06-03 Spring Boot跨域难题终结者:3种方案,从此告别CORS噩梦!
- 2025-06-03 京东大佬问我,SpringBoot为什么会出现跨域问题?如何解决?
- 2025-06-03 在 Spring Boot3 中轻松解决接口跨域访问问题
- 2025-06-03 最常见五种跨域解决方案(常见跨域及其解决方案)
- 2025-06-03 Java Web开发中优雅应对跨域问题(java跨域问题解决办法)
- 2025-06-03 Spring Boot跨域问题终极解决方案:3种方案彻底告别CORS错误
- 2025-06-03 Spring Cloud 轻松解决跨域,别再乱用了
- 2024-09-27 ASP.NET实战007:MVC解决跨域请求问题详解
- 2024-09-27 一文带你彻底搞懂跨域那些事(不只会用)
- 2024-09-27 程序员如何处理跨域问题,记住这一点就够了
你 发表评论:
欢迎- 489℃几个Oracle空值处理函数 oracle处理null值的函数
- 485℃Oracle分析函数之Lag和Lead()使用
- 483℃Oracle数据库的单、多行函数 oracle执行多个sql语句
- 469℃0497-如何将Kerberos的CDH6.1从Oracle JDK 1.8迁移至OpenJDK 1.8
- 464℃Oracle 12c PDB迁移(一) oracle迁移到oceanbase
- 458℃【数据统计分析】详解Oracle分组函数之CUBE
- 441℃Oracle有哪些常见的函数? oracle中常用的函数
- 436℃最佳实践 | 提效 47 倍,制造业生产 Oracle 迁移替换
- 最近发表
-
- Spring Boot跨域难题终结者:3种方案,从此告别CORS噩梦!
- 京东大佬问我,SpringBoot为什么会出现跨域问题?如何解决?
- 在 Spring Boot3 中轻松解决接口跨域访问问题
- 最常见五种跨域解决方案(常见跨域及其解决方案)
- Java Web开发中优雅应对跨域问题(java跨域问题解决办法)
- Spring Boot解决跨域最全指南:从入门到放弃?不,到根治!
- Spring Boot跨域问题终极解决方案:3种方案彻底告别CORS错误
- Spring Cloud 轻松解决跨域,别再乱用了
- Github 太狠了,居然把 "master" 干掉了
- IntelliJ IDEA 调试 Java 8,实在太香了
- 标签列表
-
- 前端设计模式 (75)
- 前端性能优化 (51)
- 前端模板 (66)
- 前端跨域 (52)
- 前端缓存 (63)
- 前端react (48)
- 前端aes加密 (58)
- 前端脚手架 (56)
- 前端md5加密 (54)
- 前端富文本编辑器 (47)
- 前端路由 (55)
- 前端数组 (65)
- 前端定时器 (47)
- Oracle RAC (73)
- oracle恢复 (76)
- oracle 删除表 (48)
- oracle 用户名 (74)
- oracle 工具 (55)
- oracle 内存 (50)
- oracle 导出表 (57)
- oracle 中文 (51)
- oracle链接 (47)
- oracle的函数 (57)
- 前端调试 (52)
- 前端登录页面 (48)
本文暂时没有评论,来添加一个吧(●'◡'●)