Nginx 实现基于 Cookie 的灰度路由应使用 http 块中的 map 指令提取 Cookie 值映射为变量,再通过 proxy_pass 动态路由至对应 upstream;严禁在 server 或 location 中用 if + set 分流,避免 502 等风险。
Nginx 在 Virtual Host(即 server 块)中实现基于 Cookie 的灰度路由,不能直接在 server 或 location 内用 if + set 做核心分流——这是最新明确不推荐的高危写法,容易引发 502、变量未定义、逻辑错乱等问题。正确做法是:把分流逻辑前置到 http 块,用 map 提前提取并映射 Cookie 值为变量,再在 server 中干净调用。
以下为可落地、生产可用的配置结构:
# 1. 在 http 块顶层(不能放在 server 或 location 里)定义 maphttp {# 从 $http_cookie 字符串中正则匹配 gray= 后的值(忽略大小写)map $http_cookie $upstream_backend {default "backend-stable"; # 默认走旧版~*gray=v2"backend-canary";# 匹配 gray=v2~*gray=canary"backend-canary";~*uid=abc123 "backend-canary";# 可扩展:按用户 ID 灰度}# 2. 定义 upstream(必须提前声明,不能动态拼接)upstream backend-stable {server 192.168.1.10:8080 max_fails=2 fail_timeout=30s;}upstream backend-canary {server 192.168.1.11:8080 max_fails=2 fail_timeout=30s;}# 3. server 块中直接使用已映射变量server {listen 80;server_name example.com;location / {proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;# 关键:proxy_pass 后跟变量名,对应 upstream 名proxy_pass http://$upstream_backend;# 可选:透传灰度标识给后端proxy_set_header X-Gray-Version $upstream_backend;}}}
map 必须写在 http { } 最外层,不能嵌套在 server 或 location 里;$http_cookie 是原始 Cookie 字符串(如 gray=v2; user_id=abc; path=/),Nginx 不自动解析成 $cookie_gray,除非你启用了 underscores_in_headers on 且 Cookie 名不含特殊字符;~*(忽略大小写),否则 Gray=v2 就匹配不上;default 分支必不可少,否则未匹配时 $upstream_backend 为空,proxy_pass http:// 后跟空值会直接 502;upstream 名必须与 map 中字符串完全一致,且只能是已定义的块名,不支持运行时拼接(如 proxy_pass http://backend_$env 是非法的);curl -H "Cookie: gray=v2" http://example.com/,别依赖浏览器——浏览器可能带多余 Cookie 或缓存旧值。ip_hash 或 hash $cookie_xxx,它们会覆盖 map 的分流逻辑;X-Gray-Version Header 判断流量归属,便于日志标记、功能开关或数据隔离。基本上就这些。配置简洁,逻辑清晰,也经得起高并发验证。