map指令必须定义在http块顶层,变量名以$开头且仅支持内置变量或已声明map变量,匹配区分大小写,空cookie需显式default分支,proxy_pass须引用upstream名而非url,不支持正则捕获或灰度分流。

map 指令必须在 http 块里定义,不能放 server 或 location 里
很多人一上来就在 server 块里写 map $cookie_abtest $backend,Nginx 直接报错:unknown directive "map"。这是因为 map 是 http 级指令,只允许出现在 http 块顶层(即 server 外层),和 upstream 同级。
实操建议:
- 打开
/etc/nginx/nginx.conf,找到http {开头的位置,在它内部、所有server前定义map - 变量名必须以
$开头,且只能引用内置变量(如$cookie_xxx、$arg_xxx)或已声明的 map 变量 - 匹配值区分大小写,
"v2"和"V2"是两个不同分支
Cookie 值为空或不存在时,默认走 default 分支,不是跳过
如果用户没带 abtest Cookie,$cookie_abtest 的值是空字符串 "",而不是未定义。这时候如果你没写 default,Nginx 会把空值当作一个独立 key 去匹配 —— 而你几乎肯定没为 "" 显式配置,结果变量值变成空,后续 proxy_pass http://$backend 就会崩成 invalid URL prefix 错误。
实操建议:
- 务必显式写
default "prod";,别依赖隐式 fallback - 用
""单独匹配空值也可以,但不如default直观可靠 - 测试时用
curl -H "Cookie: abtest=v2" http://example.com和curl http://example.com对比输出,确认空 Cookie 走的是预期后端
proxy_pass 引用 map 变量时,后端地址必须是 upstream 名,不能是裸 URL
常见错误是这么写:proxy_pass http://$backend;,然后在 map 里设 "v2" "https://10.0.1.5:8080";。Nginx 不允许在 proxy_pass 中动态拼接协议+地址,只接受 upstream 名或固定字符串。否则报错:invalid URL prefix in proxy_pass。
实操建议:
- 先定义好
upstream块:upstream backend_prod { server 10.0.1.1:8080; },upstream backend_v2 { server 10.0.1.5:8080; } - map 中只映射 upstream 名:
"v2" "backend_v2"; default "backend_prod"; - proxy_pass 写成
proxy_pass http://$backend;—— 这里的$backend必须对应 upstream 名,不能带路径或协议
Map 不支持正则捕获或复杂逻辑,需要多层 map 或外部模块才能做灰度比例分流
map 本质是静态键值映射,只能做精确匹配或简单前缀/后缀判断(靠 ~*)。想实现“10% 用户随机进 v2”,它做不到;想根据 Cookie 里 JSON 字段取值,也做不到。硬塞 ~* "^v2.*" 只能覆盖简单模式,没法解析结构化数据。
实操建议:
- 纯 Cookie 值路由(如
abtest=v2)用map完全够用,轻量又高效 - 要按百分比灰度,得用
split_clients指令配合$remote_addr或$cookie_id做哈希分流 - 真要解析 Cookie 里的 JSON 或做条件组合(比如
abtest=v2 AND geo=CN),就得上 OpenResty + Lua,或者把灰度逻辑下沉到应用层
真正容易被忽略的是:map 变量在 Nginx 配置重载时才生效,改完 cookie 规则必须 nginx -s reload,而不仅仅是重启 worker。线上切流前,记得先验证 map 输出是否符合预期,可以用 log_format 把 $backend 打进 access log 看一眼。










