这是一个非常典型的 Nginx 配置需求,通常用于解决防止重复添加 CORS 头的问题。核心逻辑是判断请求头是否存在,如果不存在才添加。
在 Nginx 中,我们无法直接通过 if 语句来判断某个 HTTP 响应头是否已存在(因为 if 主要针对变量和请求信息)。因此,最优雅且通用的解决方案是利用 map 指令结合变量来实现逻辑判断。
以下是具体的配置方案:
核心配置逻辑
你需要将这段配置放在 Nginx 配置文件(通常是 nginx.conf 或站点配置文件)的 http 块中。
1# 1. 使用 map 模块定义逻辑
2# $sent_http_access_control_allow_origin 是 Nginx 的内置变量,代表已经发送的 Access-Control-Allow-Origin 头值
3map $sent_http_access_control_allow_origin $cors_header {
4 # 如果已经有该头(值不为空),则变量值为空
5 "" "https://yanshi2.toone.com.cn"; # 如果为空(即没有该头),则设置为目标域名
6 # 如果已经有值(即已有该头),则保持原样,不进行操作(这里设为空,配合下面的 default 指令)
7 default "";
8}
应用到 Server/Location 块
定义好变量后,你需要将其应用到具体的 server 或 location 块中。
1server {
2 listen 80;
3 server_name your-domain.com;
4
5 # 2. 在需要的地方引用变量
6 # 注意:必须使用 add_header 指令,并且不能有 always 标志,否则会覆盖
7 # 如果你希望强制添加(例如处理预检请求),请确保逻辑正确
8 add_header Access-Control-Allow-Origin $cors_header always;
9
10 # ... 其他配置
11}
配置原理详解
-
map指令:- 它创建了一个映射关系。这里我们检查
$sent_http_access_control_allow_origin。 - 如果该变量为空字符串(意味着 Nginx 尚未设置过这个头),
$cors_header就会被赋值为https://yanshi2.toone.com.cn。 - 如果该变量不为空(意味着已经有代码或之前的配置设置了这个头),
$cors_header就会被赋值为空。
- 它创建了一个映射关系。这里我们检查
-
add_header指令:- 当
add_header的值为空时,Nginx 会忽略这条指令,不会添加头。 - 当
add_header的值为https://yanshi2.toone.com.cn时,Nginx 会添加该头。 - 注意 :如果你的后端应用(如 Node.js、Java 等)已经添加了
*,Nginx 的这个配置将不会覆盖它,从而实现了"有则不加,无则添加"的逻辑。
- 当
⚠️ 特殊情况处理(针对预检请求)
如果你的场景涉及复杂的 CORS 请求(如带有自定义头的请求),浏览器会先发送 OPTIONS 预检请求。你可能需要显式处理这些请求,确保预检请求也能正确返回头信息:
1location / {
2 # 处理预检请求
3 if ($request_method = 'OPTIONS') {
4 add_header Access-Control-Allow-Origin $cors_header;
5 add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
6 add_header Access-Control-Allow-Headers 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
7 add_header Access-Control-Max-Age 1728000;
8 add_header Content-Type 'text/plain charset=UTF-8';
9 add_header Content-Length 0;
10 return 204;
11 }
12
13 # 处理正常请求
14 add_header Access-Control-Allow-Origin $cors_header;
15}
建议: 在修改配置后,请务必运行 nginx -t 测试配置语法,并重载服务 nginx -s reload 以使更改生效。