跨域问题(CORS,Cross-Origin Resource Sharing)是 Web 研发中常见问题。当浏览器从一个源(origin)向另一个源发起请求时,出于安全思考,会受到同源策略(Same-Origin Policy)的限制。
本文将从 Spring MVC配置 + Nginx 配置 + Axios 前端调用最常规的组合解析如果通过配置解决跨域问题。
一、Spring MVC 服务端配置 CORS
方法 1:使用 @CrossOrigin注解(适用于单个 Controller 或方法)
@RestController
@CrossOrigin(origins = "http://localhost:3000") // 允许来自该源的请求
public class MyController {
@GetMapping("/api/data")
public String getData() {
return "Hello CORS";
}
}
- origins:指定允许的源,可以是数组(多个源),也可以是 “*”(不推荐用于带凭证的请求)
- 也可以加在方法上,粒度更细
方法 2:全局配置(推荐)
方式 A:通过 WebMvcConfigurer实现
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**") // 匹配需要跨域的路径
.allowedOrigins("http://localhost:3000") // 允许的源
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true) // 是否允许携带 Cookie
.maxAge(3600); // 预检请求缓存时间(秒)
}
}
⚠️ 注意:如果 allowCredentials(true),则 allowedOrigins 不能为 “*”,必须指定具体域名。
方式 B:通过 CorsFilter(更底层,适用于所有请求)
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("http://localhost:3000");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config); // 对所有路径生效
return new CorsFilter(source);
}
二、Nginx 配置 CORS(作为反向代理)
如果你使用 Nginx 作为反向代理(例如前端部署在 Nginx,后端 API 也通过 Nginx 代理),可以在 Nginx 层统一处理 CORS,减轻后端压力。
示例配置:
server {
listen 80;
server_name your-domain.com;
location /api/ {
# 添加 CORS 头
add_header 'Access-Control-Allow-Origin' 'http://localhost:3000' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, 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;
# 处理预检请求(OPTIONS)
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
# 代理到后端 Spring Boot 服务
proxy_pass http://backend-server:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
✅ 关键点:
always 参数确保即使 4xx/5xx 响应也包含 CORS 头。
OPTIONS 请求必须返回 204,否则浏览器会报错。
如果后端已经处理了 CORS,Nginx 不要重复设置,避免冲突(尤其是
Access-Control-Allow-Origin 重复)。
三、前端 Axios 配置
1. 基本请求(不带凭证)
axios.get('http://your-api.com/api/data')
.then(res => console.log(res))
.catch(err => console.error(err));
2. 携带 Cookie / 认证信息(需前后端配合)
axios.get('http://your-api.com/api/data', { withCredentials: true // 关键:允许跨域携带 Cookie
})
⚠️ 注意:
如果使用 withCredentials: true,服务端必须设置
Access-Control-Allow-Credentials: true
且
Access-Control-Allow-Origin不能为 *,必须是具体域名(如 http://localhost:3000)
3. 自定义请求头(会触发预检 OPTIONS 请求)
axios.post('http://your-api.com/api/data', { name: 'test' }, {
headers: {
'Authorization': 'Bearer xxx',
'Content-Type': 'application/json'
},
withCredentials: true
})
四、常见问题排查
|
问题 |
缘由 |
解决方案 |
|
CORS header ‘Access-Control-Allow-Origin’ missing |
服务端未返回 CORS 头 |
检查 Spring 或 Nginx 配置 |
|
Credentials flag is ‘true’, but the ‘Access-Control-Allow-Origin’ header is ‘*’ |
withCredentials=true 但 origin 为 * |
改为具体域名 |
|
Preflight response is not successful |
OPTIONS 请求未正确处理 |
确保服务端或 Nginx 返回 204 并包含 CORS 头 |
|
Nginx 配置了 CORS 但无效 |
后端也返回了 CORS 头导致冲突 |
只保留一处(提议统一在 Nginx 或后端) |
五、最佳实践提议
|
场景 |
推荐方案 |
|
开发环境 |
Spring MVC 全局 addCorsMappings,快速调试 |
|
生产环境 |
Nginx 反向代理 + 统一 CORS 配置,安全可控 |
|
前端开发 |
使用 Axios 实例封装,配置 withCredentials 和 baseURL |
✅ 终极提议:在生产环境中,不要依赖后端直接处理跨域,而是通过 Nginx 反向代理,让前后端“看起来”是同源的,这才是最安全、最稳定的方案。












- 最新
- 最热
只看作者