前后端分离时,在 Nginx 反向代理层统一添加 CORS 头,比在每个后端框架里单独配置更集中可控。
基础配置
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://backend-server:8002;
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;
# CORS 响应头
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS, PATCH" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type, Accept, X-Requested-With" always;
# OPTIONS 预检请求直接返回 204
if ($request_method = OPTIONS) {
return 204;
}
}
}
always 参数确保 CORS 头在 4xx/5xx 错误响应中也会附加。
带 Credentials 时不能用通配符
Access-Control-Allow-Origin: * 不能与 Access-Control-Allow-Credentials: true 同时使用,浏览器会拒绝:
# 错误:浏览器拒绝
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Credentials true always;
需要改为动态匹配请求来源:
add_header Access-Control-Allow-Origin $http_origin always;
add_header Access-Control-Allow-Credentials true always;
add_header Vary Origin always;
Vary: Origin 告知缓存层不同 Origin 的响应不同,防止缓存污染。
多域名白名单:map 方案
允许特定域名列表访问(带 Credentials):
map $http_origin $cors_origin {
default "";
"~^https?://localhost(:\d+)?$" $http_origin;
"~^https://app\.example\.com$" $http_origin;
"~^https://admin\.example\.com$" $http_origin;
}
server {
location /api/ {
proxy_pass http://backend-server:8002;
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Credentials true always;
add_header Vary Origin always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
if ($request_method = OPTIONS) {
return 204;
}
}
}
非白名单来源 $cors_origin 为空字符串,不会添加 CORS 头,浏览器拒绝跨域请求。
常见坑
proxy_pass 末尾斜杠影响路径
proxy_pass http://backend:8002; # /api/users → /api/users
proxy_pass http://backend:8002/; # /api/users → //users(多了斜杠)
后端已有 CORS 头导致重复
如果后端也返回了 CORS 头,Nginx 再叠加会导致响应中出现两个 Access-Control-Allow-Origin,浏览器拒绝。需要在后端关闭 CORS,统一由 Nginx 管理:
proxy_hide_header Access-Control-Allow-Origin;
add_header Access-Control-Allow-Origin $cors_origin always;