Nginx内部重定向默认只记一次access日志,需通过自定义log_format记录$request_uri与$uri等变量来追溯路径变化,并对高风险location单独启用debug日志以避免干扰主日志。

Location 内部重定向(如 try_files、rewrite ... last、internal named location)本身不产生 HTTP 状态码跳转,请求仍在 Nginx 内部流转,因此默认只记一次 access 日志——即原始请求的那条。但问题常出在:你**想看清重定向过程中的路径变化**,或**怀疑内部循环导致 500 却没日志佐证**,这时“日志不丢失”实际是指“关键中间状态可追溯”,而非物理丢数据。
用 $request_uri 和 $uri 区分原始与最终路径
access_log 默认记录的是原始请求的 $request_uri(含参数),但内部重定向后真实处理路径可能已变。要同时看到两者,需自定义日志格式:
- 在
http块中添加:
log_format debug_redirect '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$request_uri" "$uri" "$request_filename" "$args";' - 在对应
location中启用:
access_log /var/log/nginx/internal_redirect.log debug_redirect; -
$request_uri始终是客户端发来的原始 URI;$uri是重写/匹配后的内部路径;$request_filename能看出是否落到真实文件,帮你判断try_files是否 fallback 成功
对高风险 location 单独标记日志
全局开启 debug 日志性能损耗大,建议只对含 try_files、rewrite ... last 或 if 的 location 打标:
- 在
http块顶部定义变量:
map $request_uri $log_internal { default 0; ~^/(api|app|admin) 1; } - 在目标
location中:
access_log /var/log/nginx/internal_debug.log debug_redirect if=$log_internal; - 这样只有匹配路径的请求才进独立日志,便于比对原始请求和内部跳转结果,避免干扰主日志
避免 internal location 导致日志“消失”的错觉
使用 location @name { internal; ... } 时,Nginx 不会为该块单独记 access log——它只是内部跳转终点。日志仍归属原始 location。若发现“跳过去就没日志了”,常见原因有:
- @named location 中用了
proxy_pass但后端超时/返回异常,Nginx 可能只记 error log,access log 仍记原始请求(状态码可能是 502/504) - 配置了
access_log off;在父 location 或 server 块里,会关闭所有子块日志 - 日志路径权限不对或磁盘满,导致写入失败且静默丢弃(检查
error.log是否有 open() "/var/log/nginx/..." failed)
验证内部重定向是否真被记录
不要只看日志文件有没有新行,要确认内容是否反映内部行为:
- 发起请求:
curl "http://example.com/test?x=1" - 若配置了
try_files $uri @fallback;且$uri不存在,日志中$uri应为/test,$request_filename为对应磁盘路径(如/usr/share/nginx/html/test),而$status若为 200,说明@fallback成功处理 - 若
$status是 500,再查error.log是否有 rewrite or internal redirection cycle,配合debug_redirect日志定位哪次last触发了第 10 次循环











