$uri 是最合适的变量,因它天然剥离查询参数并完成uri解码、冗余斜杠合并、. / .. 处理,且保留末尾斜杠,直接满足规范化路径提取需求。

在 Nginx 中,$uri 变量天然就是剥离了查询参数(即 ?xxx 部分)的规范化请求路径,它不包含协议、域名、端口、查询字符串,也不含末尾多余的斜杠(已标准化)。因此,直接使用 $uri 就能满足“仅提取剥离查询参数的规范化请求路径”的需求。
为什么 $uri 是最合适的变量
$uri 是 Nginx 内置变量,表示当前请求经过 URI 解码和标准化(normalization)后的路径部分。它的行为包括:
- 自动移除查询字符串(
?key=value及之后内容) - 对路径做解码(如
%20→ 空格) - 合并冗余斜杠(如
/a//b/→/a/b/) - 处理
. / ..(如/a/../b→/b) - 保留末尾斜杠(如根路径
/或目录路径/api/)
如何在 access_log 中使用
在 log_format 中直接引用 $uri 即可:
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request_method $uri $server_protocol" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent"';
这样记录的日志中,第二段路径字段就是干净的规范化路径,例如:
- 请求
GET /api/v1/users?id=123&sort=name HTTP/1.1→ 记录为"GET /api/v1/users HTTP/1.1" - 请求
GET /static//css/../style.css?_v=2 HTTP/1.1→ 记录为"GET /static/style.css HTTP/1.1"
注意不要混淆的其他变量
常见误用是混用以下变量:
-
$request_uri:原始完整 URI,含查询参数,不适合本场景 -
$document_uri:等价于$uri,可用但不推荐(语义不如$uri清晰) -
$args或$query_string:只存查询参数,不能替代路径提取 -
$request:整行请求行(含方法、URI、协议),需额外解析
进阶:需要进一步标准化(如统一去尾斜杠)
若业务要求所有路径都不带末尾斜杠(如将 /admin/ 视为 /admin),$uri 本身不处理这点。此时可通过 map 指令预处理:
map $uri $clean_uri {
~^(.+)/$ $1;
default $uri;
}
然后在 log_format 中用 $clean_uri 替代 $uri。但多数日志分析系统(如 ELK、Prometheus + nginxlog exporter)更倾向保留原始路径结构,因此默认用 $uri 即可。











