跨域解决方案
一、什么是跨域?
跨域是指浏览器在发起请求时,请求的协议、域名、端口三者中,只要有一个与当前页面的地址不同,就会被浏览器拦截。
判断规则
以当前页面 http://localhost:8080 为例:
| 请求地址 | 是否跨域 | 原因 |
|---|---|---|
http://localhost:8080/api |
❌ 同源 | 协议、域名、端口完全一致 |
https://localhost:8080/api |
✅ 跨域 | 协议不同(http vs https) |
http://api.example.com/api |
✅ 跨域 | 域名不同 |
http://localhost:3000/api |
✅ 跨域 | 端口不同(8080 vs 3000) |
跨域的本质
跨域不是后端拒绝了你,是浏览器拦截了响应。
浏览器发请求 → 后端正常处理并返回数据 → 浏览器检查是否跨域
↓
跨域 → 浏览器拦截数据,抛错
同源 → 正常交给前端代码
为什么要有跨域限制?
浏览器的同源策略,是为了保护用户安全。举个例子:
你登录了 bank.com,浏览器保存了登录 Cookie
↓
你不小心打开了 hacker.com
↓
如果没有同源策略,hacker.com 的 JS 可以:
- 读取 bank.com 的 Cookie
- 伪造转账请求
- 窃取你的账户信息
同源策略就是浏览器的安全门卫,防止恶意网站窃取数据。
二、怎么解决跨域?
方案一:后端配置 CORS(最推荐,生产首选)
原理:后端在响应头中告诉浏览器:“这个跨域请求是我允许的,放行。”
Spring Boot 配置方式
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**") // 允许跨域的路径
.allowedOriginPatterns("*") // 允许所有来源(生产环境建议指定具体域名)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true) // 允许携带 Cookie
.maxAge(3600); // 预检请求缓存时间(秒)
}
}
Nginx 配置方式
server {
listen 80;
server_name api.example.com;
location / {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
add_header Access-Control-Allow-Headers 'Content-Type, Authorization';
if ($request_method = 'OPTIONS') {
return 204;
}
proxy_pass http://localhost:8080;
}
}
方案二:前端代理(开发环境首选)
原理:前端请求同源的代理服务器,代理服务器转发到后端(服务器间通信不受同源策略限制)。
Vue 项目配置(vue.config.js)
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8090', // 后端地址
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
}
React 项目配置(setupProxy.js)
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api',
createProxyMiddleware({
target: 'http://localhost:8090',
changeOrigin: true,
})
);
};
方案三:Nginx 反向代理(生产环境首选)
原理:前端和 Nginx 同源,Nginx 转发请求到后端,浏览器不感知跨域。
server {
listen 80;
server_name www.example.com;
# 前端静态文件
root /var/www/html;
index index.html;
# 反向代理后端接口
location /api/ {
proxy_pass http://localhost:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 处理前端路由(history 模式)
location / {
try_files $uri $uri/ /index.html;
}
}
三、三种方案对比
| 方案 | 适用环境 | 优点 | 缺点 |
|---|---|---|---|
| 后端 CORS | 生产环境 | 配置简单,标准方案 | 需要后端配合 |
| 前端代理 | 开发环境 | 无需后端配合,快速调试 | 仅开发环境有效 |
| Nginx 反向代理 | 生产环境 | 隐藏后端地址,性能好 | 需要运维配置 |
四、常见踩坑点
| 问题 | 原因 | 解决方案 |
|---|---|---|
allowedOrigins("*") 报错 |
与 allowCredentials(true) 冲突 |
改用 allowedOriginPatterns("*") |
| OPTIONS 请求返回 403 | 后端没处理预检请求 | 在拦截器中放行 OPTIONS 请求 |
| 带 Cookie 跨域失败 | 前端没设置 withCredentials: true |
前端设置 axios.defaults.withCredentials = true |
| 生产环境跨域 | 前端代理只在开发环境生效 | 改用 Nginx 反向代理或后端 CORS |
五、一句话总结
跨域是浏览器同源策略导致的拦截,不是后端的问题。解决方案有三种:后端配 CORS(生产推荐)、前端配代理(开发推荐)、Nginx 反向代理(生产推荐)。记住核心原则:跨域问题必须由服务端解决,前端代码改不了。

浙公网安备 33010602011771号