Nginx反向代理解决跨域
Nginx反向代理是生产环境解决跨域问题的常用方案,无需修改后端代码。
原理分析
nginx
浏览器 --> Nginx(同源) --> 后端服务
同源请求 跨域转发
浏览器只与Nginx交互,通过同源策略检查,跨域问题由Nginx内部解决。
基础配置
统一入口代理
JavaScript
server {
listen 80;
server_name example.com;
# 前端静态资源
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
# API代理到后端
location /api/ {
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;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
前端请求示例:
nginx
// 浏览器访问 http://example.com
// API请求直接发往同源地址
fetch('/api/users') // 实际请求 http://backend-server:8080/users
响应头配置方案
添加CORS响应头
nginx
server {
listen 80;
server_name api.example.com;
location / {
# 后端服务地址
proxy_pass http://localhost:8080;
# CORS配置
add_header Access-Control-Allow-Origin $http_origin always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
add_header Access-Control-Allow-Credentials true always;
add_header Access-Control-Max-Age 3600 always;
# 处理预检请求
if ($request_method = OPTIONS) {
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Max-Age 3600;
add_header Content-Length 0;
return 204;
}
}
}
动态Origin白名单
使用map指令
nginx
# 定义允许的源映射
map $http_origin $cors_origin {
default "";
"http://localhost:3000" "http://localhost:3000";
"http://localhost:4000" "http://localhost:4000";
"http://example.com" "http://example.com";
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://localhost:8080;
# 使用映射变量
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
add_header Access-Control-Allow-Credentials true always;
if ($request_method = OPTIONS) {
add_header Access-Control-Allow-Origin $cors_origin;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
add_header Access-Control-Allow-Credentials true;
add_header Content-Length 0;
return 204;
}
}
}
多服务代理配置
nginx
server {
listen 80;
server_name example.com;
# 前端应用
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}
# 用户服务
location /api/user/ {
proxy_pass http://user-service:8081/;
}
# 订单服务
location /api/order/ {
proxy_pass http://order-service:8082/;
}
# 商品服务
location /api/product/ {
proxy_pass http://product-service:8083/;
}
}
WebSocket支持
text
location /ws/ {
proxy_pass http://backend:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 86400;
}
方案对比
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 反向代理 | 无需修改代码,统一入口 | 增加Nginx层 | 生产环境 |
| 响应头配置 | 灵活控制 | 需处理预检 | 前后端分离 |
| 动态白名单 | 安全可控 | 配置复杂 | 多前端源 |
要点总结
- 反向代理通过统一入口解决跨域,浏览器无需关心后端地址
- 使用map指令可实现动态Origin白名单
- 预检请求需要单独处理返回204
- 生产环境推荐使用反向代理方案
- 配置WebSocket时需要添加升级头
📝 发现内容有误?点击此处直接编辑