map指令必须定义在http块顶层,不可置于server或location中;需用带引号和~前缀的正则匹配$arg_token参数,proxy_pass须配合同名upstream使用,通过$backend_cluster变量实现动态路由。

map 指令必须在 http 块顶层定义,不能放在 server 或 location 里
这是最常踩的坑:很多人把 map 写在 server 块里,Nginx 启动直接报错 unknown directive "map"。因为 map 是变量映射指令,只允许出现在 http 上下文中。
正确做法是打开主配置(如 /etc/nginx/nginx.conf),在 http { ... } 块内顶部附近添加:
http {
map $arg_token $backend_cluster {
default "default_backend";
"~^dev_[a-f0-9]{8}" "dev_cluster";
"~^stg_[a-f0-9]{8}" "stg_cluster";
"~^prod_[a-f0-9]{8}" "prod_cluster";
}
# 其他配置...
}注意:$arg_token 是 Nginx 内置变量,自动提取 URL 查询参数 token=xxx;$backend_cluster 是你自定义的变量名,后续会在 proxy_pass 中引用。
正则匹配要加引号,且必须用波浪线 ~ 开头
如果不加引号,Nginx 会把 dev_ 当作字面量字符串匹配,无法触发正则;不加 ~,就变成精确字符串匹配,dev_12345678 和 dev_12345678abc 都不会命中。
- ✅ 正确:
"~^dev_[a-f0-9]{8}$"—— 严格匹配 8 位十六进制前缀 - ❌ 错误:
~^dev_[a-f0-9]{8}(缺引号,语法错误) - ❌ 错误:
"dev_[a-f0-9]{8}"(缺~,变成字面量匹配) - ⚠️ 注意:
map不支持^和$以外的锚点(如\b),也不支持反向引用
proxy_pass 必须配合 upstream 使用,不能直接写域名
proxy_pass 不接受变量拼接的完整 URL(如 http://$backend_cluster:8080),否则会报错 invalid URL prefix。必须预先定义好 upstream 块,并让变量值对应 upstream 名称。
在同一个 http 块中补充:
upstream default_backend {
server 10.0.1.10:8080;
}
upstream dev_cluster {
server 10.0.2.20:8080;
server 10.0.2.21:8080;
}
upstream stg_cluster {
server 10.0.3.30:8080;
}
upstream prod_cluster {
server 10.0.4.40:8080;
server 10.0.4.41:8080;
server 10.0.4.42:8080;
}然后在 server 块里使用:
location /api/ {
proxy_pass http://$backend_cluster;
proxy_set_header Host $host;
}这里 $backend_cluster 的值(如 "dev_cluster")会直接作为 upstream 名解析,Nginx 自动做负载均衡。
调试时用 $backend_cluster 记录日志,避免盲猜分流结果
上线前务必验证分流逻辑是否生效。在 log_format 中加入变量,例如:
log_format debug '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" "$arg_token" "$backend_cluster"';再在 access_log 中启用该格式:
access_log /var/log/nginx/debug.log debug;
然后发起请求测试:
-
curl 'https://example.com/api/user?token=dev_abcd1234'→ 日志中应看到"dev_abcd1234" "dev_cluster" -
curl 'https://example.com/api/user?token=xyz'→ 应看到"xyz" "default_backend"
如果 $backend_cluster 总是空或为 default,优先检查 map 是否加载(Nginx reload 后执行 nginx -t)、$arg_token 是否被其他 rewrite 清空、URL 中 token 是否被代理层提前剥离。
map 的匹配是静态编译期确定的,不支持运行时查数据库或调用外部脚本;所有分支必须提前穷举,动态策略只能靠正则覆盖范围来模拟。


















