Nginx反向代理解决跨域问题详解
核心原理
Nginx反向代理解决跨域的核心思路是让客户端请求同域名下的接口,由Nginx将请求转发到目标服务器,从而规避浏览器的同源策略限制。
客户端(同源:www.domain.com)
↓
Nginx(同源:www.domain.com)
↓
目标服务器(跨域:api.external.com)
完整配置与代码示例
基本反向代理配置
nginx
# /etc/nginx/conf.d/default.conf
server {
listen 80;
server_name mydomain.com; # 前端域名
# 前端静态资源
location / {
root /usr/share/nginx/html;
index index.html;
}
# 接口代理配置
location /api {
# 后端实际地址(跨域的目标服务器)
proxy_pass http://api.external.com;
# 设置必要的请求头
proxy_set_header Host $proxy_host; # 保留原始Host
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# CORS支持(可选)
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization' always;
add_header 'Access-Control-Allow-Credentials' 'true' 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;
}
}
}
关键配置解析
-
proxy_pass:
nginxlocation /api { proxy_pass http://api.external.com; }
- 所有以
/api
开头的请求都会被转发到http://api.external.com
- 所有以
-
请求头保留:
nginxproxy_set_header Host $proxy_host; # 保留原始主机头 proxy_set_header X-Real-IP $remote_addr; # 保留客户端真实IP
-
CORS支持:
nginxadd_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
- 直接从Nginx层支持CORS,后端服务不需要额外处理
-
OPTIONS请求处理:
nginxif ($request_method = 'OPTIONS') { add_header 'Access-Control-Max-Age' 1728000; # ... return 204; }
- 直接响应预检请求,减轻后端服务器压力
常见场景定制配置
场景1:URL重写(删除API前缀)
nginx
location /api {
# 重写路径:移除/api前缀
rewrite ^/api/(.*)$ /$1 break;
proxy_pass http://api.external.com;
}
场景2:添加API前缀
nginx
location /user-service {
# 添加/api前缀
rewrite ^/user-service/(.*)$ /api/$1 break;
proxy_pass http://api.external.com;
}
场景3:负载均衡
nginx
upstream backend {
server backend1.example.com:8080 weight=3; # 权重
server backend2.example.com:8081;
server backup.example.com:8082 backup; # 备用服务器
}
location /api {
proxy_pass http://backend; # 使用负载均衡器
proxy_set_header Host $host;
}
场景4:WebSocket支持
nginx
location /socket {
proxy_pass http://ws-server.com;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
前端代码示例
javascript
// 请求代理路径(不再需要直接访问跨域地址)
const API_BASE = '/api'; // 与Nginx配置中的location匹配
// GET请求示例
async function getData() {
try {
const response = await fetch(`${API_BASE}/data`, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
});
return await response.json();
} catch (error) {
console.error('Error fetching data:', error);
}
}
// POST请求示例
async function postData(data) {
try {
const response = await fetch(`${API_BASE}/save`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify(data)
});
return await response.json();
} catch (error) {
console.error('Error posting data:', error);
}
}
完整操作流程
-
安装Nginx:
bash# Ubuntu/Debian sudo apt update sudo apt install nginx # CentOS/RHEL sudo yum install epel-release sudo yum install nginx
-
编辑配置文件:
bashsudo nano /etc/nginx/conf.d/default.conf
添加上面的代理配置
-
测试配置:
bashsudo nginx -t
输出
syntax is ok
和test is successful
表示配置正确 -
重启Nginx:
bashsudo systemctl restart nginx # 或 sudo service nginx restart
-
部署前端项目:
bash# 将前端构建文件放入指定目录 sudo cp -R /path/to/dist /usr/share/nginx/html
-
验证访问 :
访问
http://your-domain.com
应该加载前端页面,所有API请求自动代理到目标服务
优势对比
方案 | 是否需要修改代码 | 安全性 | 性能影响 | 多服务支持 |
---|---|---|---|---|
Nginx反向代理 | ✘ | ⭐⭐⭐⭐⭐ | 几乎没有 | ⭐⭐⭐⭐⭐ |
CORS | ✔ | ⭐⭐⭐⭐ | 中等 | ⭐⭐ |
JSONP | ✔ | ⭐ | 高 | ⭐ |
Webpack代理 | ✘ (仅开发) | ⭐⭐ | 低(开发) | ⭐⭐ |
注意事项
-
路径匹配:
- 确保
location
指令的路径匹配模式与前端请求一致 - 使用正则表达式处理复杂的URL模式
- 确保
-
日志调试:
nginxlocation /api { proxy_pass http://api.external.com; access_log /var/log/nginx/api-access.log; error_log /var/log/nginx/api-error.log; }
-
超时设置:
nginxproxy_connect_timeout 60s; # 连接超时 proxy_send_timeout 60s; # 发送超时 proxy_read_timeout 180s; # 读取超时
-
Cookie传递:
nginxproxy_cookie_domain api.external.com mydomain.com; proxy_cookie_path / /api/;
-
安全限制:
- 避免完全开放的跨域(
Access-Control-Allow-Origin: *
) - 建议使用具体的域名白名单
- 避免完全开放的跨域(
Nginx反向代理是当前解决跨域问题最成熟、稳定、高性能的解决方案,特别适合生产环境使用,既能解决跨域问题,又能实现负载均衡、安全防护等额外好处。