启用 log_subrequest 后,Nginx 会单独记录子请求日志,用于排查 SSI、rewrite last、auth_request、try_files 和 ngx.location.capture 等隐式内部请求;默认主日志不记录子请求因其不经过完整网络栈。

启用 log_subrequest 后,Nginx 会将子请求(subrequest)的访问日志单独记录,这对排查内部重定向、SSI(Server Side Include)嵌入、auth_request 鉴权、try_files 回退、以及 Lua 的 ngx.location.capture 等隐式发起的请求非常关键——它们不会出现在主请求日志中,但实际消耗资源、触发逻辑、甚至引发错误。
为什么默认看不到 SSI 或内部重定向的日志
Nginx 主请求日志(access_log)只记录客户端发起的顶层 HTTP 请求。而 SSI 的 <!--# include virtual="/header.html" -->、rewrite ... last 触发的内部跳转、或 auth_request /auth 背后的鉴权请求,都是由 Nginx 内部以“子请求”方式同步执行的,不经过 client → server 的完整网络栈,因此默认不记入 access_log。
开启 log_subrequest on 后,这些子请求会按相同格式写入指定日志文件(可与主日志分离),包含独立的 $request_time、$status、$upstream_addr 等变量,真正实现“所见即所得”的调用链追踪。
如何正确启用并配置 subrequest 日志
在 http、server 或 location 块中添加:
-
log_subrequest on;—— 全局开关,必须开启 -
access_log /var/log/nginx/subrequests.log main subrequest;—— 关键:末尾加上 subrequest 标识符,表示该日志仅记录子请求 - (可选)为区分主/子日志,可另配一条不含 subrequest 标识的 access_log 记录主请求
注意:subrequest 日志中的 $request 是子请求路径(如 "/header.html"),$uri 是其解析后的内部 URI,$host 和 $remote_addr 仍继承自原始请求,$http_referer 则为空(因无真实 Referer)。
通过日志识别常见子请求类型
观察 subrequests.log 中的字段组合,可快速判断来源:
- SSI include:$request_method 通常为 GET,$status 多为 200,$request 包含 .html/.shtml 后缀,且紧随主请求后出现(时间戳接近)
- 内部重定向(rewrite last):$request 匹配 rewrite 目标路径,$status 为 000(子请求不返回状态码给客户端,Nginx 内部标记为 000),$request_time 极短
- auth_request 鉴权:$request 为配置的 auth 接口路径(如 "/auth"),$status 为 200(鉴权成功)或 401/403(失败),常伴随 $upstream_response_time
- try_files 回退:当首个文件不存在时,后续尝试的路径(如 @fallback 或 /index.php)会作为子请求记录,$status 可能为 404 或 200
实战调试建议:结合日志与配置定位问题
例如 SSI 页面部分缺失,但主日志显示 200:
- 查 subrequests.log 中对应时间点的 include 请求,看是否返回 404 或超时
- 检查该子请求的 $request_filename 是否指向真实文件;若使用 alias,确认 alias 路径拼接是否正确
- 若子请求耗时长($request_time > 1s),可能是上游服务慢或磁盘 I/O 延迟,需结合 $upstream_addr 和 $upstream_response_time 分析
- 配合
error_log /path debug;可看到更底层的 subrequest 创建/完成事件,但仅用于开发环境,线上慎用
不复杂但容易忽略。


















