使用 map 指令可动态生成变量,将路径匹配逻辑从 location 块解耦,实现统一、灵活的上游服务路由;支持正则与字符串混合匹配,按序首匹配,可在 server 或 http 块中定义,配合 proxy_pass 实现动态反向代理。

用 map 指令动态生成变量,能有效把 Location 路径匹配逻辑从硬编码中解耦出来,避免写一堆重复的 location ~ ^/xxx/ 块,也便于统一管理路径前缀与后端服务的映射关系。
用 map 提前定义路径到上游的映射关系
map 是 Nginx 的变量映射模块(需启用 ngx_http_map_module,默认已编译),它能在请求处理早期根据请求路径、Host、Header 等条件,生成一个新变量。关键在于:它的匹配是“一次性计算”,不依赖 location 顺序,且支持正则和字符串前缀混合判断。
例如,把不同 API 路径前缀映射到对应 upstream 名称:
map $request_uri $backend_upstream {
~^/api/v1/users/ users_backend;
~^/api/v1/orders/ orders_backend;
~^/api/v1/products/ products_backend;
~^/admin/ admin_backend;
default default_backend;
}
注意:$request_uri 包含完整路径+参数,若只需路径部分,可用 $uri 替代;正则匹配按顺序从上到下,遇到第一个匹配即停止。
在 location 中复用 map 变量做反向代理
有了 $backend_upstream,就可以在一个通用 location 块里完成路由分发,无需为每个路径写独立 location:
location /api/ {
proxy_pass http://$backend_upstream;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
这样所有以 /api/ 开头的请求,都会先经 map 计算出目标 upstream,再由 proxy_pass 动态转发。Nginx 会自动拼接剩余 URI(如 /api/v1/users/list → 转发到 users_backend 的 /v1/users/list)。
- 确保 upstream 已正确定义,例如:
upstream users_backend { server 10.0.1.10:8080; } - 如果需要保留原始路径前缀(比如后端依赖
/api/v1/...),可在proxy_pass后加斜杠,或用rewrite显式控制 -
map变量在server或http块中定义,不能放在location内
进阶技巧:组合多个维度做精细化路由
map 支持嵌套判断,可结合 Host、Header、甚至其他 map 变量,实现灰度、多租户或 A/B 测试路由。例如,按请求头区分内网/外网后端:
map $http_x_forwarded_for $is_internal {
~^10\.|~^192\.168\.|~^172\.(1[6-9]|2[0-9]|3[0-1])\. "1";
default "0";
}
map "$is_internal:$uri" $final_backend {
"1:/api/v1/admin/" admin_internal;
"0:/api/v1/admin/" admin_external;
"~/api/v1/.*" default_api;
}
这种写法把判断逻辑集中、可读性强,也方便后续加监控或日志标记(如 log_format 中记录 $final_backend)。
注意事项与常见坑
map 不是万能的,要注意几个边界情况:
- 正则中的捕获组(
())不会被保存,仅用于匹配;如需提取子路径,得用rewrite+set -
map的值不能直接调用函数或执行命令,纯静态映射;动态逻辑(如查 Redis)需用 Lua 或 OpenResty - 空格敏感:
map $uri $v { ~^/a/ a; ~^/b/ b; }中花括号前后不能有多余换行或空格,否则配置校验失败 - 调试时可用
add_header X-Backend $backend_upstream;临时查看变量值










