使用 map 指令可提前将路径等特征映射为变量,使 location 配置更简洁、可维护;支持多变量拼接、正则捕获、default 兜底及调试头注入。

直接用 map 指令把路径特征提前转成变量,再在 location 里引用,能大幅降低配置复杂度。它不替代 location,而是让 location 的逻辑更干净、更可维护。
把路径前缀映射为服务标识
当 API 路径和后端服务强关联时(比如 /api/v1/users → users-svc),用 map 提前提取服务名,location 就不用写一堆正则分支:
- 在 http 块中定义:
map $uri $service_name {
default "default-svc";
~^/api/v1/users/ "users-svc";
~^/api/v1/orders/ "orders-svc";
~^/api/v2/products/ "products-v2";
} - server 中只需统一转发:
location /api/ {
proxy_pass http://$service_name;
} - 好处是新增接口只需加一行 map 规则,不用动 location 结构或重复 proxy_pass 配置
组合多个变量做精细判断
单靠 $uri 有时不够,比如要区分租户+版本+环境。这时可拼接变量作为 map 输入源:
- 例如:
map "$host:$request_uri" $upstream_cluster {
default "prod-main";
~*^tenant-a\.example\.com:/api/v2/ "tenant-a-v2";
~*^staging\.example\.com:/api/ "staging-api";
} - 注意用冒号拼接,避免值重叠(如 host=ab 和 uri=cd 拼成 abcd,可能误匹配)
- 正则加 ~* 忽略大小写,防止因 Host 头大小写不一致导致路由失败
用 map 替代嵌套 if + 正则判断
location 内部用 if 匹配路径再 set 变量,不仅性能差,还容易出错。map 在请求早期一次性计算,更稳定:
- 错误做法(不推荐):
location / {
if ($request_uri ~ ^/admin/) { set $backend "admin-svc"; }
if ($request_uri ~ ^/user/) { set $backend "user-svc"; }
proxy_pass http://$backend;
} - 正确做法:用 map 统一生成 $backend,location 里只做 proxy_pass,逻辑清晰且无 if 副作用
- map 还支持捕获组,比如 ~^/v(\d+)/(.*)$ 可提取版本号 $1 和路径 $2,用于后续 header 注入或 upstream 名称构造
配合 default 避免空值风险
map 不匹配时变量为空字符串,若直接用于 proxy_pass 会报 502。显式设 default 是基本操作:
- 每条 map 都加上 default,哪怕只是 fallback 到一个基础集群:
map $arg_version $backend {
default "v1-default";
"v2" "v2-canary";
"v3" "v3-stable";
} - 也可 default 指向一个带健康检查的 upstream,确保兜底可用
- 调试时可通过 add_header X-Backend $backend 查看实际命中值,验证 map 是否生效

















