Nginx可通过map指令提取Cookie字段(如gray、user_id)映射为变量,结合if或动态upstream实现灰度路由,并注入X-Gray-Flag等请求头透传染色信息。

可以通过 Nginx 的 map 指令将 Cookie 中的特定字段(如 gray=on 或用户 ID)映射为自定义变量,再结合 if、proxy_pass 或 upstream 实现请求路由分流,从而完成轻量、无侵入的灰度发布与流量染色。
用 map 提取并标准化 Cookie 值
map 指令必须定义在 http 块中,它能根据正则或精确匹配把原始 Cookie 解析成布尔值、版本号或权重标识。关键点是使用 $cookie_* 内置变量读取 Cookie,并用默认值兜底避免未命中时变量为空:
}http {
map $cookie_gray $is_gray {
default 0;
"on" 1;
"true" 1;
"~*v2" 2; # 支持正则匹配灰度版本
}
<pre class="brush:php;toolbar:false;">map $cookie_user_id $user_group {
default "default";
"~*^(\d{1,3})" $1; # 提取用户 ID 前三位做分组依据
"~*abc.*" "test"; # 匹配特定用户标识
}
按变量值动态选择上游服务
利用 map 输出的变量控制 proxy_pass 目标,实现不同灰度标识走不同后端集群。推荐配合 upstream 定义多套后端,再用变量拼接 server 名称或直接判断路由:
}upstream backend_stable {
server 10.0.1.10:8080;
}
<p>upstream backend_gray_v2 {
server 10.0.1.20:8080;
}</p><p>server {
location /api/ {</p><h1>方式一:用 if + proxy_pass(简单场景)</h1><pre class="brush:php;toolbar:false;"> if ($is_gray = 1) {
proxy_pass http://backend_gray_v2;
break;
}
if ($is_gray = 2) {
proxy_pass http://backend_gray_v2;
proxy_set_header X-Gray-Version "v2";
break;
}
proxy_pass http://backend_stable;
# 方式二:更健壮的 upstream name 动态拼接(需启用 nginx-plus 或 OpenResty)
# set $upstream_name "backend_${is_gray}";
# proxy_pass http://$upstream_name;
}
结合 rewrite 实现流量染色透传
灰度流量需要下游服务识别,仅靠 Cookie 不够可靠(可能被客户端清除或不透传)。应在转发前注入明确的请求头,例如 X-Gray-Flag 和 X-User-Group,让后端统一读取:
}server {
location / {
# 注入灰度标识头
proxy_set_header X-Gray-Flag $is_gray;
proxy_set_header X-User-Group $user_group;
<pre class="brush:php;toolbar:false;"> # 可选:重写 URL 添加 query 参数用于调试(如 ?gray=v2)
# if ($is_gray) {
# rewrite ^(.*)$ $1?gray=$is_gray&$args break;
# }
proxy_pass http://backend_stable;
}
注意事项与避坑提示
map 是惰性求值,只在变量首次被引用时执行;它不能放在 server 或 location 块内;Cookie 值区分大小写,map 默认区分,可用 ~* 开头做忽略大小写匹配;if 在 location 中慎用,避免嵌套和重复执行问题;生产环境建议搭配日志记录灰度决策过程,便于排查:
log_format gray_log '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'gray="$is_gray" group="$user_group"';
<p>access_log /var/log/nginx/gray_access.log gray_log;</p>











