nginx配置跨域规则详解及代码示例教程
详细讲解Nginx配置跨域资源共享(CORS)的核心指令、配置步骤与代码示例,涵盖简单请求、预检请求、携带Cookie场景及生产环境多域名匹配方案。
当前后端分离部署在不同域名、端口或协议下时,前端浏览器发起的异步请求会受到同源策略的拦截。解决这一问题的常见且高效的做法是在接入层使用 Nginx 设置跨域资源共享(CORS)响应头,或通过反向代理将跨域请求转发为同源请求。本文将详细讲解 Nginx 中跨域规则的核心配置指令、完整语法示例、多场景下的配置细节与验证排查步骤。
一、跨域的核心机制与 Nginx 处理逻辑
同源策略是浏览器端执行的一套安全机制。当发起请求的网页源(协议、域名、端口三者构成的元组)与目标接口的源不一致时,即产生跨域。CORS 机制允许服务器通过在响应中返回特定的 HTTP 响应头,明确告知浏览器允许哪些源访问该资源。
浏览器将跨域请求分为“简单请求”与“非简单请求”。对于使用了自定义 Header(如 Authorization、token)或请求体为 application/json 的复杂请求,浏览器在发送正式业务请求前,会先行发送一个 OPTIONS 方法的“预检请求”(Preflight Request)。如果服务器对该预检请求未能返回包含跨域许可标头的 204 或 200 响应,浏览器就会阻断随后的业务请求并报出 CORS 错误。
二、核心响应头指令含义
在 Nginx 中,主要使用 ngx_http_headers_module 模块提供的 add_header 指令向客户端注入所需的跨域标头。配置前需要明确以下关键响应头的含义与规范:
- Access-Control-Allow-Origin:指定允许访问资源的调用源。可以配置为通配符
*(允许任意源),或具体的源地址如https://app.example.com。 - Access-Control-Allow-Methods:指定允许的跨域请求方法列表,常见取值为
GET, POST, PUT, DELETE, OPTIONS。 - Access-Control-Allow-Headers:指定允许客户端请求携带的自定义头部字段,如
DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization。 - Access-Control-Allow-Credentials:布尔值,指定是否允许前端跨域携带凭证(如 Cookie、HTTP 认证信息)。注意:如果该项设为
true,则Access-Control-Allow-Origin不能设置为通配符*,必须为明确的 Origin 字符串。 - Access-Control-Max-Age:指定本次预检请求的有效期(秒)。在有效期内,浏览器不需要为相同的跨域请求再次发送预检请求,能显著降低服务端请求量。
三、通用跨域配置代码示例
下面的配置示例展示了一个生产环境中通用的 location 块。该配置支持常见 HTTP 方法、携带自定义头,并在 Nginx 层直接处理 OPTIONS 请求后返回 204 No Content,无需将预检流量穿透到后端服务。
server {
listen 80;
server_name api.example.com;
location / {
# 允许的请求源,这里以单个域名为例
add_header 'Access-Control-Allow-Origin' 'https://www.example.com' always;
# 允许携带认证信息(如 Cookie)
add_header 'Access-Control-Allow-Credentials' 'true' always;
# 允许的请求方式
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, PATCH, 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,token' always;
# 允许前端脚本访问的额外响应头
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
# 针对预检请求 (OPTIONS) 进行单独处理
if ($request_method = 'OPTIONS') {
# 预检缓存时间:1728000 秒(20天)
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://127.0.0.1:9000;
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;
}
}
always在 Nginx 中,
add_header 指令默认仅对 200, 201, 204, 206, 301, 302, 303, 304, 307 或 308 等常规状态码生效。如果后端返回了 400、404、500 等错误状态码,未加 always 时 Nginx 会剥离自定义标头,导致前端抓取到的是莫名其妙的 CORS 报错,掩盖了真实业务错误。在每个 add_header 后面添加 always 可以确保无论返回何种状态码,跨域头都正常输出。
四、操作步骤:从编辑配置到热重载
为了让新配置在生产环境中平稳上线,需要遵循规范的操作流程,避免语法错误导致服务中断。
第一步:打开站点配置文件。 根据具体的 Linux 发行版或容器挂载路径,配置文件通常位于 /etc/nginx/nginx.conf 或 /etc/nginx/conf.d/ 目录下对应的 .conf 文件。
sudo vim /etc/nginx/conf.d/api.conf
第二步:在对应的 location 节点中加入规则。 将第三节或后文特定场景的配置写入该 location 内部。
第三步:测试配置文件语法。 保存退出后,切勿直接重启服务,先执行测试命令检测是否存在语法拼写错误或分号缺失:
sudo nginx -t
输出示例:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
第四步:重载 Nginx 服务。 验证无误后,发送平滑重载信号使新规则生效,无需中断已有连接:
sudo nginx -s reload
# 或者通过 systemd 管理:
sudo systemctl reload nginx
五、生产环境高频场景与进阶配置
1. 允许多个指定域名跨域(动态匹配)
在实际生产环境中,Access-Control-Allow-Origin 不宜设置为通配符 *,但有时需要同时支持开发环境、测试环境以及多个不同子域名访问。直接写多个 add_header Access-Control-Allow-Origin ... 会导致响应头重复并被浏览器拒绝。此时可使用 Nginx 的 map 模块进行动态映射:
# 该指令必须置于 http {} 块中,与 server {} 块同级
map $http_origin $cors_origin {
default "";
"~^https?://(www\.)?example\.com$" "$http_origin";
"~^https?://admin\.example\.com$" "$http_origin";
"~^https?://localhost(:[0-9]+)?$" "$http_origin";
}
server {
listen 80;
server_name api.example.com;
location / {
# 当请求源在白名单内时,$cors_origin 将赋值为当前请求源,否则为空
add_header 'Access-Control-Allow-Origin' $cors_origin always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always;
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With' always;
if ($request_method = 'OPTIONS') {
# 只有匹配成功的域名才返回 204
if ($cors_origin != "") {
add_header 'Access-Control-Allow-Origin' $cors_origin always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always;
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With' always;
add_header 'Access-Control-Max-Age' 1728000;
return 204;
}
return 403;
}
proxy_pass http://127.0.0.1:9000;
}
}
2. 反向代理同源化(免配置 CORS 标头)
如果前端和接口由同一个 Nginx 服务提供路由,最彻底规避跨域的方式是利用 Nginx 反向代理将请求收敛到同源下,使浏览器根本不会触发跨域检查:
server {
listen 80;
server_name www.example.com;
# 静态前端页面托管在根路径
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
# 前端代码内请求接口一律发往 /api/,由 Nginx 代理到底层服务
location /api/ {
proxy_pass http://127.0.0.1:9000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
六、配置结果验证与故障排查
配置并重载后,可通过命令行工具 curl 进行快速测试,验证返回的响应头是否符合预期。
1. 测试预检请求(OPTIONS)是否正常返回 204:
curl -I -X OPTIONS http://api.example.com/data \
-H "Origin: https://www.example.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: Authorization,Content-Type"
示例输出:
HTTP/1.1 204 No Content
Server: nginx/1.24.0
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
Access-Control-Allow-Headers: DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,token
Access-Control-Max-Age: 1728000
Content-Length: 0
2. 常见问题排查清单:
- 报错:The 'Access-Control-Allow-Origin' header contains multiple values
原因:后端代码(如 Spring Boot、Express)与 Nginx 同时添加了该响应头。跨域规范不允许该标头出现多个逗号分隔的源。解决方法是只保留接入层(Nginx)统一添加,或者在 Nginx 中使用proxy_hide_header Access-Control-Allow-Origin;屏蔽后端输出。 - 报错:Credentials flag is 'true', but the 'Access-Control-Allow-Origin' header is '*'
原因:当设置了Access-Control-Allow-Credentials: true时,跨域规范强制要求Access-Control-Allow-Origin必须是单一具体的源字符串,不能是通配符*。请按前述教程替换为确定域名或利用map指令按需注入。 - 后端抛出 500 错误时提示 CORS 错误
原因:add_header缺少always参数。在错误状态码下,Nginx 没有将 CORS 头发送给浏览器,导致控制台仅显示 CORS 报错,掩盖了后端抛出的 500 异常细节。在所有add_header尾部补齐always即可正常暴露业务报错。










































