$request_uri是原始完整URI(含参数和锚点),不可修改;$uri是当前标准化路径(无参数、可被重写改变)。必须用$request_uri时:反向代理透传、原始日志记录、基于全URL的限流/鉴权;适合用$uri时:location匹配、静态服务、缓存key生成。

$request_uri 是原始请求的完整 URI,含查询参数(?key=value)和锚点(#fragment),不可修改,全程不变;$uri 是当前处理阶段的标准化路径,不含参数、不含锚点,且在重写、内部跳转或 index 指令触发后会动态变化。
什么时候必须用 $request_uri
需要保留原始请求全貌时,不能依赖 $uri:
- 做反向代理时透传完整路径(尤其带参数的 API 请求),例如:
proxy_pass http://backend$request_uri; - 记录原始访问日志用于审计或排查,避免因 rewrite 导致日志失真
- 实现基于原始 URL 的限流、黑白名单或防盗链逻辑(如校验
/api/v2/user?token=xxx整体) - 配合
map做条件判断,且规则依赖参数内容(如区分/search?q=nginx和/search?q=redis)
什么时候更适合用 $uri
关注资源路径结构、不关心参数时,$uri 更稳定可靠:
- location 匹配后的路径判断,比如
location /static/ { ... }中,后续逻辑只需知道是否落在/static/下 - 静态文件服务或索引页跳转(如访问
/admin/自动找/admin/index.html),Nginx 内部已归一化路径 - 生成缓存 key 时需排除参数干扰(如页面模板缓存),可搭配
$uri$is_args$args精确控制 - rewrite 规则中作为匹配目标或替换依据,因其反映当前上下文路径状态
常见误用与踩坑点
混淆二者会导致行为不符合预期:
- 用
$uri做 proxy_pass 透传:参数丢失,后端收不到?id=123 - 在
if ($uri = "/login") { ... }中判断,但用户实际访问/login?next=/home,结果不匹配(因为 $uri 是/login,但 if 条件没考虑参数存在性) - 日志格式里混用:若同时记录 $request_uri 和 $uri,发现相同请求下两者值不同,却误以为配置出错
- 使用
try_files $uri @fallback时,$uri 已是重写后路径,而你本意想 fallback 到原始请求逻辑 —— 此时应改用 $request_uri + rewrite 或自定义变量保存原始值
生产建议:明确意图,分层使用
不要“默认选一个”,而是按用途分层设计:
- 入口层(access_log、geo、map、limit_req)优先用
$request_uri,保真溯源 - 路由层(location、rewrite、try_files)多用
$uri,语义清晰、性能轻量 - 代理层(proxy_pass、fastcgi_param)看需求:要透传就用
$request_uri;要过滤参数或加前缀,可用$uri$is_args$args组合构造 - 调试时可在 log_format 中同时输出两者,快速定位 rewrite 或 internal redirect 是否影响路径语义











