Nginx中动态设置响应头应使用map指令生成变量再注入add_header,map须定义在http块且需default分支,支持精确/正则匹配,适用于按域名、Origin、参数等场景。

直接在 add_header 里写条件判断是不行的,Nginx 不支持表达式语法。真正可靠、可维护的做法,是用 map 指令先生成变量,再把变量注入到 add_header 中——这是 Nginx 官方推荐的动态头控制方式。
核心思路:先映射,再注入
map 必须定义在 http 块(不能在 server 或 location 内),它根据输入变量(如 $host、$http_origin、$arg_env)查表生成一个新变量,这个新变量后续可在 add_header、proxy_set_header 等支持变量的指令中使用。
- 每个
map块需有default分支,否则未匹配时变量为空,可能导致头缺失或配置异常 - 支持精确匹配和正则匹配(用
~或~*开头) - 生成的变量是字符串类型,可直接拼接或原样输出
按域名设置自定义响应头
适用于多租户、多环境 API 网关等场景,比如给不同子域打上服务标识:
http {
map $host $x_service_name {
api.example.com "api-service";
admin.example.com "admin-panel";
tenant-a.example.com "tenant-a";
default "unknown";
}
}
然后在对应 server 块中写:
server {
server_name api.example.com;
add_header X-Service-Name $x_service_name;
add_header X-Env "production";
}
这样 api.example.com 的响应里就会带 X-Service-Name: api-service,而其他域名走默认值。
按来源 Origin 动态开启 CORS 头
这是跨域配置最安全的做法,避免硬编码或滥用 *:
http {
map $http_origin $cors_origin {
default "";
"~*^https?://(localhost|127\.0\.0\.1):[0-9]+$" "$http_origin";
"~*^https?://(app\.example\.com|dashboard\.staging\.org)$" "$http_origin";
}
}
在 location 中启用:
location /api/ {
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' 'DNT,Content-Type,Authorization' always;
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 86400 always;
add_header 'Content-Length' 0 always;
add_header 'Content-Type' 'text/plain; charset=utf-8' always;
return 204;
}
}
注意:always 标志必不可少,否则 204、404 等非 2xx 响应不会携带这些头,预检会失败。
按请求参数或 Cookie 注入调试头
便于后端识别流量来源,比如标记灰度用户或测试环境:
http {
map $arg_debug $x_debug_flag {
"1" "true";
"true" "true";
default "false";
}
map $cookie_user_role $x_role_hint {
"admin" "admin-session";
"guest" "guest-session";
default "anonymous";
}
}
然后在响应中透出:
location / {
add_header X-Debug-Mode $x_debug_flag;
add_header X-User-Role $x_role_hint;
}
前端开发者加 ?debug=1,后端就能在日志或监控中快速识别该请求是否处于调试路径。


















