Nginx通过map指令结合正则匹配动态设置Access-Control-Allow-Origin,支持多域名、子域名及开发环境;需拦截非法Origin并显式处理OPTIONS预检请求,启用credentials时禁止通配符且必须精确匹配。

在 Nginx 中实现跨域(CORS)时,硬编码 Access-Control-Allow-Origin 值无法应对多域名、动态子域名或第三方回调场景。利用 Nginx 变量配合正则匹配,可实现对授权域名的模糊匹配与安全放行,兼顾灵活性与安全性。
用 map 指令预定义可信域名模式
Nginx 的 map 指令支持基于正则的变量映射,适合集中管理跨域白名单规则。它在 server 启动时编译,性能开销极低,且可复用。
在 http 块中添加:
map $http_origin $cors_origin {
default "";
"~^https?://(app\.example\.com|dashboard\.example\.org|.*\.myplatform\.io)$" $http_origin;
"~^https?://localhost:3000$" $http_origin;
}说明:
-
$http_origin是客户端请求头中的 Origin 值; - 正则前加
~^表示大小写敏感的开头匹配; - 支持通配符子域名(如
.*\.myplatform\.io),但不匹配 IP 或无协议值; - 未匹配时设为
"",后续可据此拒绝响应。
在 location 中动态设置 CORS 响应头
在需要跨域的 location 块中,用 $cors_origin 控制响应头输出:
location /api/ {
if ($cors_origin = "") {
return 403;
}
<pre class="brush:php;toolbar:false;">add_header 'Access-Control-Allow-Origin' $cors_origin;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
# 处理预检请求
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 http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
注意:
- 务必先做
if ($cors_origin = "")拦截,防止空 Origin 或非法来源绕过; -
add_header在非 2xx/3xx 响应中默认不生效,所以return 403不会带 CORS 头; - 预检请求(OPTIONS)需显式返回 204,并设置必要头,避免浏览器拦截后续请求。
进阶:支持凭证(withCredentials)的安全限制
当前端设置 credentials: 'include' 时,Nginx 必须同时满足:
-
Access-Control-Allow-Origin不能为*; - 必须显式设置
Access-Control-Allow-Credentials: true; - Origin 必须精确匹配,不可用通配符(如
*.example.com不合法)。
因此,若需支持凭据,建议将子域名白名单收窄为具体匹配:
map $http_origin $cors_origin_with_cred {
default "";
"~^https?://(app\.example\.com|admin\.example\.com|staging\.example\.com)$" $http_origin;
}
<h1>在 location 中:</h1><p>if ($cors_origin_with_cred = "") {
return 403;
}
add_header 'Access-Control-Allow-Origin' $cors_origin_with_cred;
add_header 'Access-Control-Allow-Credentials' 'true';</p>此时,localhost:3000 等开发环境也需单独列入,否则浏览器会因凭证策略拒绝响应。
验证与调试技巧
跨域配置易出错,推荐以下验证方式:
- 用
curl -H "Origin: https://app.example.com" -I https://your-api.com/api/test检查响应头是否含正确Access-Control-Allow-Origin; - 故意传入非法 Origin(如
https://hacker.com),确认返回 403 且无 CORS 头; - 打开浏览器开发者工具 → Network → 查看预检请求(OPTIONS)是否返回 204 及完整 CORS 头;
- 检查 Nginx 错误日志:
tail -f /var/log/nginx/error.log,排查 map 匹配失败或语法错误。
不复杂但容易忽略。










