Nginx 的 proxy_pass 本身不支持条件判断,但可通过 map 指令基于 Host、URI、Header、参数等动态映射后端 upstream,实现高效路由;map 在 http 块中定义,仅初始化执行一次,开销小,支持正则、字符串匹配及多层嵌套组合条件。

Nginx 的 proxy_pass 本身不支持条件判断,但配合 map 指令可以实现基于请求特征(如 Host、URI、Header、参数等)的动态代理目标,这是生产中常用且高效的做法。
map 指令的作用和基本写法
map 是 Nginx 的变量映射模块(需启用 ngx_http_map_module,默认已编译),它在 http 块中定义,将某个源变量按规则映射为新变量,且只在请求初始化阶段执行一次,开销极小。
例如,根据 Host 头选择后端集群:
http {
map $host $backend_upstream {
hostnames;
default backend_default;
example.com backend_v1;
api.example.com backend_api;
~^v\d+\.api\.example\.com$ backend_versioned;
}
upstream backend_default { server 10.0.1.10:8080; }
upstream backend_v1 { server 10.0.1.11:8080; }
upstream backend_api { server 10.0.1.12:8080; }
upstream backend_versioned { server 10.0.1.13:8080; }
server {
listen 80;
location / {
proxy_pass http://$backend_upstream;
proxy_set_header Host $host;
}
}
}结合 URI、Query 参数或 Header 做路由
map 支持正则、字符串匹配、嵌套逻辑(通过多层 map 或使用空值占位),可灵活提取路由依据:
⚠️ 已弃用 — 该技能已拆分为两个独立技能,以提升模块化程度:**webchat-https-proxy**(HTTPS/WSS 反向代理)和 **webchat-voi...**
- 用
$request_uri匹配路径前缀:map $request_uri $target_service { ~^/admin/ admin_backend; ~^/api/v2/ v2_api; } - 用
$arg_env读取 URL 参数:map $arg_env $env_route { "prod" "prod-svc"; "staging" "staging-svc"; default "default-svc"; },再在proxy_pass http://$env_route中使用 - 用
$http_x_forwarded_for或自定义 Header 实现灰度:map $http_x_release_channel $upstream_choice { "canary" canary_backend; default main_backend; }
注意事项与常见陷阱
map 变量必须在 http 块顶层定义,不能放在 server 或 location 内;且映射结果不能是带协议或端口的完整 URL,仅能作为 proxy_pass 的 upstream 名或 IP:PORT 字符串。
-
proxy_pass后跟变量时,若变量含端口(如"10.0.1.10:8080"),Nginx 会自动识别;若只写域名(如"backend_v1"),必须提前定义对应的upstream块 - 正则匹配以
~开头(区分大小写)或~*(忽略大小写),注意转义点号、斜杠等特殊字符 - 避免在 map 中直接拼接
http://——proxy_pass不接受这种写法,会报错 “invalid URL prefix” - 调试时可用
add_header X-Backend $backend_upstream;返回所选后端,方便验证逻辑
进阶:多维条件组合(模拟 if)
Nginx 不建议在 location 中用 if 做复杂判断,但可通过嵌套 map 实现“与”逻辑。例如:同时按 Host 和 URI 路由:
map $host $host_type {
example.com site_a;
app.example.com site_b;
default site_default;
}
map $host_type$request_uri $final_upstream {
~^site_a/admin/ admin_a;
~^site_b/api/ api_b;
~^site_default/ default_backend;
default default_backend;
}然后 proxy_pass http://$final_upstream 即可生效。这种方式比 if + set 更稳定、更高效。










