nginx中proxy_pass仅支持$scheme、$host、$request_uri、$uri、$args及正则捕获变量(如$1、$service),不支持自定义set变量或拼接URL;推荐用正则location捕获或map指令预定义映射。

nginx 的 proxy_pass 在 location 块中直接使用变量(如 $host、$arg_backend 或自定义 $backend)是受限的,**只有部分变量被允许,且必须满足特定条件**。它不是所有变量都能用,也不能在任意上下文中自由拼接 URL。
哪些变量可以在 proxy_pass 中安全使用
nginx 官方明确支持在 proxy_pass 中使用的变量仅限于:
– $scheme(http/https)
– $host(请求头 Host 字段,注意缓存行为)
– $request_uri(完整 URI,含 query string)
– $uri(解码后的路径,不含 query)
– $args(query string 部分)
– 正则捕获变量 $1、$2 等(需配合正则 location)
⚠️ 不支持:
– 自定义 set $backend "xxx" 定义的变量(会报错:"invalid URL prefix")
– 拼接字符串如 http://$backend:8080/$uri(语法非法)
– 使用 $upstream_addr、$sent_http_xxx 等响应阶段变量
合法用法示例:基于正则捕获动态代理
这是最常用也最稳妥的动态代理方式:
- 用正则 location 匹配路径并提取目标服务名
- 将捕获组直接用于
proxy_pass
例如,把 /api/v1/users 代理到 http://users-service:8080/v1/users:
location ~ ^/api/(?<service>[a-z]+)/(?<path>.*)$ {
proxy_pass http://$service-service:8080/$path;
proxy_set_header Host $service-service;
}</path></service>
说明:
– (? 捕获 service 名(如 users)
– $service 是 nginx 原生支持的命名捕获变量,可直接用于 proxy_pass
– $path 替换原始路径中匹配后的剩余部分
替代方案:用 map 指令预定义映射关系
当需要根据域名、参数或 header 动态选后端时,推荐用 map 预先定义变量,再在 proxy_pass 中引用(仅限 http 块中定义):
http {
map $arg_backend $upstream_host {
default "127.0.0.1:8080";
"user" "user-svc:8000";
"order" "order-svc:8001";
}
server {
location /api/ {
proxy_pass http://$upstream_host;
}
}
}
✅ 这种写法合法,因为 map 创建的变量属于 nginx 内置支持的“可展开变量”,且在解析配置阶段就已确定值域。
❌ 直接 set $upstream_host "user-svc:8000" + proxy_pass http://$upstream_host 会失败。
不推荐但可行的兜底方案:rewrite + proxy_pass 固定地址
如果逻辑复杂、变量来源不可控,可先用 rewrite 改写 URI,再用静态 proxy_pass 转发:
location /route/ {
rewrite ^/route/(?<target>[^/]+)/(.*)$ /$2 break;
proxy_pass http://$target-service;
}</target>
⚠️ 注意:
– 这里 $target 是正则捕获,合法;
– 但 http://$target-service 实际仍非法(变量不能出现在协议+域名位置);
– 所以更稳妥的是改用 map 或 upstream 配合 proxy_pass 引用 upstream 名称。











