nginx基于cookie分流的核心是用map指令提取$cookie_uid变量并映射后端upstream,需定义在http块内,配合proxy_pass动态路由,同时透传原始cookie并修正domain/path以确保会话一致。

nginx 实现基于 cookie 的分流,核心是读取客户端请求中的 Cookie 值,再根据该值动态选择后端 upstream。推荐使用 map 指令,它语义清晰、性能稳定、配置简洁,比 if + set 更安全可靠。
用 map 提取并映射 Cookie 值
map 必须定义在 http 块内,不能放在 server 或 location 中。它通过匹配 $COOKIE_XXX 变量(自动提取名为 XXX 的 Cookie)生成新变量,用于后续 proxy_pass。
- 假设你要读取名为
uid的 Cookie,值为1001或1002,分别对应两套测试环境 - 配置示例:
http {
map $COOKIE_uid $backend_group {
~^1001$ backend_v1;
~^1002$ backend_v2;
default backend_default;
}
upstream backend_v1 {
server 192.168.1.10:8080;
}
upstream backend_v2 {
server 192.168.1.11:8080;
}
upstream backend_default {
server 192.168.1.12:8080;
}
server {
listen 80;
location / {
proxy_pass http://$backend_group;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
注意:$COOKIE_uid 是 nginx 内置变量,会自动提取请求头中 Cookie: uid=1001; ... 的值;正则匹配用 ~^1001$ 可避免子串误匹配(如 10012 被错判为 1001)。
处理多值或复杂匹配场景
当 Cookie 值含分号、空格或需按规则提取(如取最后一位、匹配前缀),可结合正则捕获与默认兜底:
- 匹配以
expid=开头、结尾是1或2的值(常见灰度标识): map $http_cookie $group { ~*expid=([^;]+)1(;|$) v1; ~*expid=([^;]+)2(;|$) v2; default default; }- 若 Cookie 未携带目标字段,
$COOKIE_xxx为空字符串,会命中 default 分支
确保 Cookie 正确透传给后端
分流只是第一步,后端服务要能收到原始 Cookie 才能维持会话。需显式开启透传:
-
proxy_set_header Cookie $http_cookie;—— 强制转发原始 Cookie 头(默认已继承,但显式声明更稳妥) - 若后端域名与前端不一致(如代理到 test.example.com),还需修正 Cookie 的 Domain 属性:
-
proxy_cookie_domain ~^(.+)$ $1;或proxy_cookie_domain .example.com .yourdomain.com; - 跨域时务必加
proxy_cookie_path / /;避免路径不匹配导致 Cookie 被丢弃
验证与调试技巧
分流是否生效,关键看日志和实际响应:
- 在 log_format 中加入变量,例如:
"group=$backend_group cookie_uid=$COOKIE_uid" - 用浏览器插件(如 EditThisCookie)手动设置 Cookie,刷新页面观察响应内容是否切换
- 用 curl 测试:
curl -H "Cookie: uid=1001" http://your-domain/,对比 uid=1002 的返回 - 检查后端 access_log,确认请求确实到达了预期的 upstream 机器











