启用 log_subrequest 后,nginx 会记录子请求日志,包括 rewrite last 重定向、ssi 包含、mirror 镜像等内部动作,配合 $request_id 和 $subrequest 变量可完整追踪单次用户请求的全链路。

启用 log_subrequest 后,Nginx 会将子请求(subrequest)的访问日志也写入 access_log,包括内部重定向(如 rewrite ... last)、SSI(Server Side Include)包含、mirror 指令触发的镜像请求等。这能帮你清晰看到“一次用户请求背后到底发起了哪些内部动作”,是调试复杂请求流程的关键手段。
一、确认 log_subrequest 已开启并配置可区分的日志格式
Nginx 默认不记录子请求日志。需在 http 或 server 块中显式开启,并建议用自定义日志格式标出子请求来源:
log_format subreq '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'req_id="$request_id" '
'subreq="$subrequest";';
<p>access_log /var/log/nginx/access.log subreq;
log_subrequest on; # ? 关键:必须启用
</p>注意:$subrequest 变量仅在子请求中为 "1",主请求中为空。配合 $request_id(需 ngx_http_core_module 支持),可把同一用户请求下的所有主/子请求串起来分析。
二、追踪 rewrite + last 触发的内部重定向
当使用 rewrite ... last 时,Nginx 会发起子请求重新匹配 location,此时该子请求会被记录($subrequest="1"):
location /old {
rewrite ^/old/(.*)$ /new/$1 last;
}
location /new {
return 200 "served from /new\n";
}
访问 /old/test 时,日志中会出现两条记录:
- 主请求:
"GET /old/test HTTP/1.1" 200 ... subreq="" - 子请求:
"GET /new/test HTTP/1.0" 200 ... subreq="1"(注意协议是 HTTP/1.0,这是 Nginx 子请求的特征)
通过比对 $request_id,你能确认这两条日志属于同一次客户端请求,从而验证重定向路径是否符合预期。
三、捕获 SSI 包含(include virtual)的真实执行链
SSI 的 <!--# include virtual="/fragment.html" --> 会触发一个子请求去获取片段内容。开启 log_subrequest 后,这个包含动作将被完整记录:
location / {
ssi on;
ssi_types text/html;
}
location = /fragment.html {
return 200 "dynamic-fragment";
}
当用户请求一个含 SSI 的页面(如 /page.html),日志中会看到:
- 主请求:
"GET /page.html HTTP/1.1" 200 ... subreq="" - SSI 子请求:
"GET /fragment.html HTTP/1.0" 200 ... subreq="1"
若 fragment 返回 404 或超时,你能在子请求日志里第一时间定位问题位置,而不是只看到主页面返回空白或错误状态码。
四、看清 mirror 镜像请求的触发时机与行为
mirror 指令会异步发起一个镜像子请求(不影响主请求响应),它同样受 log_subrequest 控制:
location /upload {
mirror /mirror;
proxy_pass http://backend;
}
location = /mirror {
internal; # ? 必须设为 internal
proxy_pass http://logger;
}
用户上传文件时,主请求走 proxy_pass,同时后台静默发出一个镜像请求到 /mirror。日志中你会看到:
- 主请求:
"POST /upload HTTP/1.1" 200 ... subreq="" - 镜像子请求:
"POST /mirror HTTP/1.0" 200 ... subreq="1"
注意镜像请求默认使用 HTTP/1.0、无 body(除非显式配置 mirror_request_body on),这些细节都能通过子请求日志验证。
log_subrequest 不增加业务逻辑,但让 Nginx 内部调度过程变得完全可观测。结合 request_id 和自定义日志字段,你就能在真实流量中精准还原每个复杂请求的完整生命周期。











