$request_uri是Nginx中表示客户端原始请求完整URI(含查询参数)的只读内置变量,常用于精准匹配、重写和路由控制,但需注意其包含query string、不自动解码、不可赋值等特性,推荐结合location、map、$args等机制安全高效使用。

在 Nginx 中,$request_uri 是一个内置变量,表示客户端原始请求的完整 URI(含查询参数),例如 /api/v1/users?id=123。它常用于精准匹配或重写路径,但要注意它**包含 query string**,而 $uri 不包含。配置转发规则时,需结合 if、rewrite 或 location 等指令合理使用,避免常见陷阱。
用 if + $request_uri 做条件判断转发
适用于简单、明确的 URI 匹配场景(如拦截带特定参数的请求)。注意:if 在 location 外不推荐滥用,且不能嵌套。
- 匹配以
/old-path开头且含?ref=abc的请求,转发到新地址:
if ($request_uri ~ ^/old-path(.*)\?ref=abc$) {
return 301 https://example.com/new-path$1;
}
- 更安全的做法是先用
location =精确匹配路径,再用$args单独处理参数,避免正则复杂化。
用 rewrite 结合 $request_uri 重写并内部转发
当需要保留原始 query string 并修改路径结构时,$request_uri 可直接用于 rewrite 目标(Nginx 1.11.8+ 支持),但需加 break 或 last 控制后续处理流程。
- 将所有
/mobile/xxx请求(含参数)内部转发到/api/xxx:
rewrite ^/mobile(/.*)?$ $request_uri break;
然后配合 location 捕获:
location /mobile/ {
rewrite ^/mobile(/.*)?$ /api$1 last;
}
- 注意:直接用
$request_uri作 rewrite 目标时,Nginx 不会自动解码或规范化,确保源 URI 是预期格式。
用 location 配合 $request_uri 做精细化控制
location 本身不直接支持 $request_uri,但可在其内部通过 if 或 map 实现灵活路由。推荐用 map 提前定义规则,性能更好、更清晰。
- 示例:根据
$request_uri决定上游服务分组:
map $request_uri $backend {
~^/admin/.*$ admin_backend;
~^/api/v2/.*\?debug=1$ debug_backend;
default default_backend;
}
upstream admin_backend { server 10.0.0.10:8080; }
upstream debug_backend { server 10.0.0.11:8080; }
upstream default_backend { server 10.0.0.12:8080; }
server {
location / {
proxy_pass http://$backend;
}
}
-
map块必须放在 http 上下文中,支持正则和默认值,比多个if更高效稳定。
注意事项与避坑提醒
$request_uri 是只读变量,不能赋值;它的值始终是客户端发送的原始 URI,不会被 decode 或标准化(如 %20 保持原样)。
- 不要在
location中直接写if ($request_uri ...)—— 除非必要,优先用location路径匹配 +$args分离参数。 - 重定向(return 301/302)时,
$request_uri可直接拼接,但需注意编码问题;内部转发(proxy_pass)建议用$uri和$args组合更可控。 - 调试时可用
log_format打印$request_uri和$uri对比,确认是否含参、是否被改写。


















