如何通过Nginx内置变量 $request_completion 准确判断客户端请求是否完整记录到日志?

2026-04-27 18:441阅读0评论SEO资讯
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计993个文字,预计阅读时间需要4分钟。

如何通过Nginx内置变量 $request_completion 准确判断客户端请求是否完整记录到日志?

Nginx 的 `$request_completion` 变量用于标识当前请求是否已被完整处理(即客户端端已正常接收完所有数据,Nginx 也已完成响应)。在日志中,它有助于识别因网络中断、客户端提前关闭连接、超时或主动取消导致的请求不完整问题。这对于排查前端加载失败、API调用异常、埋点丢失等问题非常实用。

理解 $request_completion 的取值逻辑

该变量仅在请求结束时(log 阶段)可用,取值为:

  • "OK":请求完整处理完成,包括客户端发完所有请求体(如 POST 数据)、服务端返回完整响应、TCP 连接正常关闭;
  • 空字符串(""):请求未完成,常见于客户端断连、读取请求体超时(client_body_timeout)、发送响应中途断开、或 worker 进程被强制终止等场景。

注意:$request_completion 不反映 HTTP 状态码是否为 2xx,即使返回 500,只要流程走完、响应发出,它仍为 "OK";反之,即使返回 200,若客户端在响应写入一半时关闭连接,它就是空值。

在 access_log 中添加 completion 标记

httpserverlocation 块中定义带该变量的日志格式:

log_format detailed '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '$request_completion';

然后启用日志:

access_log /var/log/nginx/access.log detailed;

日志样例:

  • 192.168.1.100 - - [10/Jul/2024:14:22:35 +0800] "POST /api/submit HTTP/1.1" 200 42 "-" "curl/8.6.0" OK
  • 192.168.1.101 - - [10/Jul/2024:14:22:37 +0800] "POST /api/submit HTTP/1.1" 200 0 "-" "Mozilla/5.0..." ""(空值表示响应未发完或请求体未收全)

结合其他变量做有效过滤与分析

单独看 $request_completion 价值有限,建议组合关键字段定位问题:

  • 筛选不完整请求:awk '$12 == "" {print}' /var/log/nginx/access.log(假设第12列为 $request_completion);
  • 重点关注大请求体未完成的情况:grep '""' access.log | awk '$10 == 0 && $9 > 10240 {print}'(响应字节数为 0 且请求体超 10KB,大概率是客户端中断上传);
  • 关联 $request_time$upstream_response_time:若 $request_time 显著大于后者,且 $request_completion 为空,说明响应阶段卡住或客户端断连;
  • 配合 $connection_requests$server_protocol 判断是否集中出现在 HTTP/1.1 长连接复用末期或 TLS 握手异常后。

注意事项与常见误判场景

该变量无法捕获所有“逻辑不完整”行为,需避免误解:

  • 客户端发起请求后立即关闭(如 JS 中 fetch().catch() 后未 await,或 Axios timeout 触发 abort),Nginx 通常记录为空,但不是所有浏览器都严格遵循 RST 行为;
  • 使用 proxy_buffering off 或流式响应(如 SSE、chunked transfer)时,$request_completion 仍只反映连接终态,不表示业务逻辑执行完毕;
  • if 或重写逻辑中提前 return,只要响应已发出,仍为 "OK";只有未进入输出阶段就终止(如读取 body 超时)才为空;
  • 该变量在 log_by_lua* 中不可用(Lua 阶段早于 log 阶段),如需 Lua 处理,请改用 ngx.ctxheader_filter_by_lua*body_filter_by_lua* 中标记,再透传至日志变量。
标签:Nginx

本文共计993个文字,预计阅读时间需要4分钟。

如何通过Nginx内置变量 $request_completion 准确判断客户端请求是否完整记录到日志?

Nginx 的 `$request_completion` 变量用于标识当前请求是否已被完整处理(即客户端端已正常接收完所有数据,Nginx 也已完成响应)。在日志中,它有助于识别因网络中断、客户端提前关闭连接、超时或主动取消导致的请求不完整问题。这对于排查前端加载失败、API调用异常、埋点丢失等问题非常实用。

理解 $request_completion 的取值逻辑

该变量仅在请求结束时(log 阶段)可用,取值为:

  • "OK":请求完整处理完成,包括客户端发完所有请求体(如 POST 数据)、服务端返回完整响应、TCP 连接正常关闭;
  • 空字符串(""):请求未完成,常见于客户端断连、读取请求体超时(client_body_timeout)、发送响应中途断开、或 worker 进程被强制终止等场景。

注意:$request_completion 不反映 HTTP 状态码是否为 2xx,即使返回 500,只要流程走完、响应发出,它仍为 "OK";反之,即使返回 200,若客户端在响应写入一半时关闭连接,它就是空值。

在 access_log 中添加 completion 标记

httpserverlocation 块中定义带该变量的日志格式:

log_format detailed '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '$request_completion';

然后启用日志:

access_log /var/log/nginx/access.log detailed;

日志样例:

  • 192.168.1.100 - - [10/Jul/2024:14:22:35 +0800] "POST /api/submit HTTP/1.1" 200 42 "-" "curl/8.6.0" OK
  • 192.168.1.101 - - [10/Jul/2024:14:22:37 +0800] "POST /api/submit HTTP/1.1" 200 0 "-" "Mozilla/5.0..." ""(空值表示响应未发完或请求体未收全)

结合其他变量做有效过滤与分析

单独看 $request_completion 价值有限,建议组合关键字段定位问题:

  • 筛选不完整请求:awk '$12 == "" {print}' /var/log/nginx/access.log(假设第12列为 $request_completion);
  • 重点关注大请求体未完成的情况:grep '""' access.log | awk '$10 == 0 && $9 > 10240 {print}'(响应字节数为 0 且请求体超 10KB,大概率是客户端中断上传);
  • 关联 $request_time$upstream_response_time:若 $request_time 显著大于后者,且 $request_completion 为空,说明响应阶段卡住或客户端断连;
  • 配合 $connection_requests$server_protocol 判断是否集中出现在 HTTP/1.1 长连接复用末期或 TLS 握手异常后。

注意事项与常见误判场景

该变量无法捕获所有“逻辑不完整”行为,需避免误解:

  • 客户端发起请求后立即关闭(如 JS 中 fetch().catch() 后未 await,或 Axios timeout 触发 abort),Nginx 通常记录为空,但不是所有浏览器都严格遵循 RST 行为;
  • 使用 proxy_buffering off 或流式响应(如 SSE、chunked transfer)时,$request_completion 仍只反映连接终态,不表示业务逻辑执行完毕;
  • if 或重写逻辑中提前 return,只要响应已发出,仍为 "OK";只有未进入输出阶段就终止(如读取 body 超时)才为空;
  • 该变量在 log_by_lua* 中不可用(Lua 阶段早于 log 阶段),如需 Lua 处理,请改用 ngx.ctxheader_filter_by_lua*body_filter_by_lua* 中标记,再透传至日志变量。
标签:Nginx