Nginx 实现根据 URL 参数转发主要依赖 location 匹配规则配合 proxy_pass 指令,动态路径需使用正则捕获变量并保留查询参数。
先说结论:通过 location 正则匹配 URL 路径片段,利用变量动态拼接 upstream 地址,必须显式保留查询参数以防丢失。
- 适合:按业务路径分流、多版本服务灰度、基于 URL 特征的请求路由
- 先准备:定义好 upstream 服务器组,确认 Nginx 版本支持变量 proxy_pass
- 验收:使用 curl 携带参数请求,检查后端接收到的完整 URL 是否符合预期
快速配置思路
若需根据 URL 路径动态转发,核心是在 location 中使用正则捕获组,并在 proxy_pass 中引用变量。
upstream backend1 { server 192.168.1.10:8080; }
upstream backend2 { server 192.168.1.11:8080; }
server {
listen 80;
# 匹配 /svr1/ 开头的路径,捕获后续内容
location ~ ^/(svr1|svr2)/(.*)$ {
# $1 代表捕获的组 1(svr1 或 svr2),$2 代表剩余路径
# $is_args$args 确保查询参数不丢失
proxy_pass http://$1/$2$is_args$args;
proxy_set_header Host $host;
}
}若逻辑复杂,可使用 map 指令预先定义路径与 upstream 的映射关系,减少 location 块内的正则开销。
为什么会这样
Nginx 请求处理遵循 location 匹配优先级,正则匹配 location 能提取路径变量供后续指令使用。
默认情况下,proxy_pass 后接域名或 IP 时,location 匹配到的部分会被替换;若接变量,则行为不同,需手动拼接路径。查询参数默认不自动传递,必须通过 $args 或 $is_args$args 显式添加,否则后端无法获取原始请求参数。公开资料中没有看到可靠的量化数据表明正则匹配对性能的具体影响比例,但复杂正则确实会增加 CPU 计算开销。
分步处理
第一步:定义后端服务器组。在 http 块内使用 upstream 模块声明后端池,支持权重和备份设置。
upstream app_server {
server 10.0.0.1:8080 weight=3;
server 10.0.0.2:8080 backup;
}第二步:配置 location 匹配规则。使用 location ~ 开启正则匹配,括号内内容可作为变量 $1, $2 引用。
location ~ ^/api/(v1|v2)/(.*)$ {
# 转发逻辑
}第三步:设置 proxy_pass 转发地址。若 upstream 名称是变量,需确保该变量在请求阶段已解析;若直接转发到 IP,注意尾部斜杠会截断路径。
# 错误示例:尾部斜杠可能导致路径丢失
proxy_pass http://backend/;
# 正确示例:变量拼接
proxy_pass http://backend/$2$is_args$args;怎么验证是否生效
使用 curl 命令模拟请求,观察响应头或后端日志确认转发目标。
curl -v http://your-nginx-ip/svr1/test?uid=123检查 Nginx 访问日志 access.log,确认 $upstream_addr 变量显示的后端 IP 是否符合预期规则。若配置了错误日志级别为 info,可查看 error.log 确认 upstream 解析过程有无报错。
常见坑
第一,查询参数丢失。若 proxy_pass 中未写 $is_args$args,问号后的参数不会传递给后端,导致业务报错。
第二,路径重复拼接。location 匹配的部分在 proxy_pass 带变量时不会自动剔除,需手动用捕获组重构路径,否则后端可能收到 /svr1/svr1/test 这样的重复路径。
第三,正则性能风险。location 正则匹配按配置顺序执行,过于复杂的正则或过多的正则 location 块会增加请求延迟,优先使用精确匹配 location = 或普通前缀匹配。
常见问题
能否根据查询参数(如?id=1)转发?
原生 Nginx 不支持直接用查询参数值选择 upstream,需借助 map 解析 $args 或使用 Lua 脚本。
proxy_pass 尾部斜杠有什么影响?
若 proxy_pass 地址以斜杠结尾,location 匹配到的路径部分会被移除;若不带斜杠,原始 URI 会完整传递。
如何保留原始 Host 头?
需显式配置 proxy_set_header Host $host,否则后端可能获取到 upstream 定义的域名而非客户端请求域名。
参考来源
- Nginx 根据 url 中的 path 动态转发到 upstream 的实现(技术社区文章,2020 年 1 月 3 日)
- Nginx 如何根据 url 中的 path 动态转发到 upstream(技术社区文章,2025 年 4 月 24 日)
- nginx 根据参数转发到不同服务器_Nginx 服务器之负载均衡策略(技术社区文章,2020 年 12 月 5 日)