Nginx通过map指令将请求特征(如请求头、参数、Cookie)映射为upstream名称变量,再由proxy_pass动态引用该变量实现路由;需在http块中定义map和多个隔离的upstream块,且变量值必须与upstream名称严格一致。

Nginx 中 Upstream 本身不直接“识别”请求特征,但可通过 upstream 分组 + map 指令 + 变量代理 的组合,实现按请求头、参数、Cookie 或路径等特征动态路由到专用后端集群。关键不在 upstream 写法本身,而在于如何把请求特征映射成 upstream 名称并交给 proxy_pass 使用。
用 map 提取请求特征并映射到 upstream 名称
map 指令在 http 块中定义,将某个请求变量(如 $arg_env、$http_x_version、$cookie_user_type)映射为一个自定义变量(如 $backend_cluster),该变量值必须与某个 upstream 块名称完全一致:
- 按 URL 参数分流(例如 ?env=staging):
map $arg_env $backend_cluster {
default prod_cluster;
staging staging_cluster;
dev dev_cluster;
} - 按请求头分流(适合内部网关调用):
map $http_x_release_phase $backend_cluster {
default v1_cluster;
canary canary_cluster;
bluegreen bg_v2_cluster;
} - 按 Cookie 实现灰度用户路由:
map $cookie_gray_id $backend_cluster {
~^[a-f0-9]{8}.* canary_cluster;
default prod_cluster;
}(支持正则匹配)
为每个用途定义独立的 upstream 块
每个逻辑集群对应一个命名明确的 upstream,彼此隔离,可单独配置权重、健康检查和算法:
- 各版本集群互不影响:
upstream prod_cluster {
server 10.0.1.10:8080 max_fails=2 fail_timeout=15s;
server 10.0.1.11:8080;
}
upstream canary_cluster {
server 10.0.2.20:8080 weight=1;
server 10.0.2.21:8080 weight=1;
} - 支持不同策略:prod_cluster 可用 least_conn,canary_cluster 可用 ip_hash 保证测试用户始终落到同一节点
- backup、down、max_fails 等参数仍可照常使用,故障处理逻辑独立生效
在 location 中通过变量引用 upstream
proxy_pass 后不能写变量表达式(如 http://$backend_cluster),必须配合 resolver 或使用命名 upstream 的间接方式。最稳妥做法是:
→ 在 server 块内用 if(仅限简单判断,避免嵌套)或更推荐——
→ 在 location 中用 proxy_pass 直接指向一个固定 upstream,而该 upstream 名称由 map 动态决定,需借助 Nginx 的“命名 upstream”特性(1.19.5+ 支持)或采用以下兼容写法:
- 定义统一入口 upstream,内部用变量跳转(需 OpenResty 或 nginx-plus)
- 主流稳定方案:用多个 location + if(慎用)或用 Lua 模块(如 lua-resty-upstream)做运行时选择
- 最简可行方案(兼容所有版本):为每种特征写独立 location,配合精确匹配和 proxy_pass 指向对应 upstream
location /api/ {
if ($arg_env = "staging") {
set $upstream_target "http://staging_cluster";
}
proxy_pass $upstream_target;
# … 其他 proxy_* 设置
}
验证与注意事项
上线前务必验证映射逻辑是否生效:
- 开启 access_log 并记录 $backend_cluster 变量,确认每次请求是否命中预期集群
- 用 curl 发送带不同参数/头的请求,观察响应头中 X-Upstream-Addr 或后端日志来源 IP
- map 不支持嵌套或复杂逻辑,复杂路由建议前置到 API 网关或用 OpenResty 的 Lua 处理
- 所有 map 必须定义在 http 块顶层,且变量名不能与内置变量冲突


















