前言
写Nginx配置的时候,$request_uri和$uri是两个出场率极高的变量。很多人分不清它们的区别,结果重定向配置出问题——参数丢了、路径错了、循环了,排查半天才发现是用错了变量。这篇文章把这两个变量彻底讲清楚。
$request_uri 和 $uri 的核心区别
先上一张对比表,一目了然:
| 变量 | 包含内容 | 查询参数 | rewrite后是否变化 |
|---|---|---|---|
$request_uri | 完整的原始请求URI | 包含 | 不变 |
$uri | 当前处理中的URI路径 | 不包含 | 会变 |
举个例子,请求 /blog/post.html?id=10&page=2:
$request_uri=/blog/post.html?id=10&page=2$uri=/blog/post.html
三个关键差异详解
1. 查询参数的有无
$request_uri自带查询参数(?key=value部分),$uri只有路径。如果你需要用到查询参数,要么用$request_uri,要么用$uri$is_args$args拼接。
这里解释一下两个辅助变量:
$is_args:如果请求有查询参数,值为?;没有则为空字符串$args:纯查询参数内容(不含?)
所以 $uri$is_args$args 和 $request_uri 看起来结果一样——但有个关键区别,往下看。
2. rewrite后的行为差异
这是最容易踩坑的地方。$request_uri是原始请求URI,不受rewrite影响;$uri会跟随rewrite变化。
location /old {
rewrite ^/old/(.*)$ /new/$1 break;
# 此时:
# $request_uri 仍然是 /old/page?xxx(原始请求)
# $uri 变成了 /new/page(rewrite后的路径)
}
这个差异在做重定向时尤其重要。如果你想重定向到新路径并保留原始查询参数,要用$request_uri;如果只需要rewrite后的路径,用$uri。
3. 尾部斜杠和标准化
$uri会经过Nginx的路径标准化处理,比如去掉重复斜杠、解析..等。而$request_uri保持用户请求的原始样子。
实战场景:什么时候用哪个
场景1:HTTP跳HTTPS保留参数
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
用$request_uri,因为要保留原始路径和查询参数。如果用$uri,查询参数就丢了。
场景2:rewrite后重定向到新路径
location /legacy {
rewrite ^/legacy/(.*)$ /v2/$1 permanent;
}
这里rewrite本身会自动处理重定向,$uri在rewrite过程中被更新,最终重定向到/v2/xxx。
场景3:日志记录原始请求
log_format main '$remote_addr - $request_uri - $uri';
同时记录两个变量,$request_uri看用户实际请求了什么,$uri看Nginx最终处理的是哪个路径。排查rewrite问题时特别有用。
场景4:条件判断区分有无参数
if ($is_args) {
return 301 https://$host$uri$is_args$args;
}
return 301 https://$host$uri;
用$is_args判断是否有参数,按需拼接。比直接用$request_uri更灵活。
常见踩坑总结
- 重定向丢参数:用了
$uri而不是$request_uri,查询参数全没了 - rewrite后重定向到旧路径:在rewrite块里用
$request_uri,结果跳回原始URL,造成循环 - return 301拼URL时多问号:同时用了
$request_uri和$is_args$args,导致URL出现两个? - if块里误用$uri:if里的
$uri可能还没经过rewrite,值不是你期望的
快速选择指南
| 需求 | 用哪个 |
|---|---|
| 重定向并保留完整原始URL | $request_uri |
| 获取rewrite后的纯路径 | $uri |
| 需要路径+参数但路径可能被rewrite | $uri$is_args$args |
| 只要查询参数 | $args |
| 判断有没有查询参数 | $is_args |
| 记录日志看原始请求 | $request_uri |
相关文章
版权声明
本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论