Nginx 的 map 指令用于预定义变量映射关系,在 server 块解析前生成确定值,必须定义在 http 块中,支持正则、字符串匹配与默认值,性能高但无法动态读取请求体或运行时函数结果。

Nginx 的 map 指令不是用来做“条件跳转”或“运行时判断”的,而是用于**预定义变量映射关系**,在请求处理早期(server 块解析前)就生成一个确定值。它配合其他指令(如 if、set、rewrite、proxy_set_header 等)才能实现高级条件逻辑,但要注意:map 本身不执行动作,只提供“查表式变量”。
map 的核心用法和限制
map 必须定义在 http 块中,不能写在 server 或 location 内;它的两个参数分别是“源变量”和“目标变量”,支持正则、字符串匹配、通配符和默认值。Nginx 启动时会编译所有 map 规则,因此性能极高,但无法动态读取请求体、cookie 多层嵌套或运行时函数结果。
- 源变量可以是内置变量(如
$host、$args、$http_user_agent),也可以是其他 map 变量(支持链式) - 不支持直接匹配请求头的某个字段值(如
$http_x_version)是否包含某子串 —— 需先用正则捕获再 map,或改用if + set - 空字符串、未匹配项默认为未定义,建议始终用
default明确兜底
用 map 实现多条件 host / path 路由分发
比如根据域名和 URL 路径组合决定后端集群,避免大量 if 嵌套(if 在 location 中有性能和语义陷阱):
http {
map "$host:$request_uri" $backend_cluster {
default "default_backend";
"~^api\.example\.com:/v1/.*" "v1_api";
"~^api\.example\.com:/v2/.*" "v2_api";
"~^admin\.example\.com:.*" "admin_ui";
"~^cdn\.example\.com:/images/.*" "cdn_images";
}
<pre class="brush:php;toolbar:false;">server {
listen 80;
location / {
proxy_pass http://$backend_cluster;
proxy_set_header Host $host;
}
}}
这里利用 $host:$request_uri 拼接构造唯一键,用正则一次匹配 host+path 组合,比用多个 if + nested map 更清晰高效。
结合 map 和 geoip / user agent 实现灰度流量标记
想对特定地区用户或新版本 UA 开启灰度功能,可先用 map 标记,再在 location 中按需启用 rewrite 或 header 注入:
map $http_user_agent $is_new_ua {
default 0;
"~*Chrome/12[0-9]" 1;
"~*Firefox/11[5-9]" 1;
}
<p>map $remote_addr $is_china_ip {
default 0;
include /etc/nginx/ip-china.conf; # 由 geoip2 或手动维护的 CIDR 列表
}</p><h1>合并条件:中国 + 新 UA → 灰度</h1><p>map "$is_china_ip:$is_new_ua" $enable_gray {
"1:1" 1;
default 0;
}</p><p>server {
location /api/ {
if ($enable_gray) {
rewrite ^/api/(.*)$ /api-gray/$1 break;
}
proxy_pass <a href="https://www.php.cn/link/b8c2bade00a02f38b6d5464e176d8e90">https://www.php.cn/link/b8c2bade00a02f38b6d5464e176d8e90</a>;
}
}注意:if 在 location 中仍需谨慎,但仅用于简单 rewrite 且基于 map 输出的布尔变量,风险可控。更推荐把灰度逻辑下沉到 upstream(如用 consistent_hash + 自定义 key)。
用 map 派生带格式的 header 或日志字段
比如将不同环境的请求打上 X-Env 标签,或生成结构化日志前缀:
map $host $env_tag {
default "prod";
"~^staging\." "staging";
"~^dev\." "dev";
"~^localhost" "local";
}
<p>map "$env_tag:$status" $log_prefix {
default "[prod]";
"staging:200" "[staging OK]";
"staging:404" "[staging MISS]";
"dev:.*" "[dev $status]";
}</p><p>log_format main '$log_prefix - $remote_addr - $request';
这样无需在每个 location 里重复 set,所有日志/响应头都自动携带上下文。也适用于动态设置 proxy_set_header X-Env $env_tag 透传给后端。
不复杂但容易忽略:map 的 key 匹配是“从上到下首个成功”,正则优先级高于字面量,default 是最后兜底;调试时可用 add_header X-Map-Debug "$env_tag"; 临时验证。真正复杂的分支逻辑(如依赖 body、多次 cookie 解析),建议交由后端或 OpenResty 处理。


















