$request_completion 是 Nginx 标识请求是否完全结束的内置变量,仅在响应体全部发送完毕且 TCP 确认后为 "ok",否则为空;据此可识别用户主动中断下载。

$request_completion 是 Nginx 日志中一个关键的内置变量,用于标识 HTTP 请求的完成状态,尤其在判断用户是否主动中断下载时具有不可替代的作用。
什么是 $request_completion
该变量取值为字符串,仅在请求**完全结束**(即响应体已全部发送完毕)时为 "ok";其余所有情况——包括客户端提前关闭连接、超时、服务端错误中断、或尚未完成响应——均为空字符串("")。
它不是布尔标志,也不反映“成功/失败”的业务逻辑,而是纯粹的**连接生命周期信号**:只有当 Nginx 真正把最后一个字节发给客户端且收到 TCP 层确认(或至少完成 write 调用),才会设为 "ok"。
如何识别用户主动中断下载
用户点击取消、关闭浏览器标签、网络断开等行为,会导致 TCP 连接异常终止。此时 Nginx 无法发出完整响应,$request_completion 保持为空。因此,判断主动中断的核心依据是:
- 日志中 $request_completion 字段为空(即未出现 "ok")
- 同时 $status 通常为 200(说明响应头已发出,下载已开始)
- 而 $bytes_sent 明显小于文件总大小(可通过 $content_length 或后端记录比对)
例如一条典型中断日志:
192.168.1.100 - - [10/Jan/2025:14:22:33 +0800] "GET /large-file.zip HTTP/1.1" 200 0 "" "" "ok" "-" "Mozilla/5.0..."
若其中 "ok" 缺失(即第六字段为空),且 $bytes_sent(第五字段)远小于预期,基本可判定用户中途停止。
配置日志格式以捕获关键信息
默认 log_format 通常不包含 $request_completion,需显式添加。推荐在 nginx.conf 的 http 块中定义:
log_format download_log '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_completion $upstream_http_content_length';
注意:
- $request_completion 必须放在固定位置(如倒数第二字段),便于脚本解析
- 补充 $upstream_http_content_length 可辅助校验原始文件大小(适用于 proxy_pass 场景)
- 若使用 fastcgi 或其他后端,改用对应 header 变量(如 $fastcgi_header_content_length)
常见误判与注意事项
- 不要依赖 $status == 200 判断下载完成:200 仅代表响应头已发出,和 body 是否发完无关
- 代理层可能掩盖中断信号:如果前端有 CDN 或负载均衡,它们可能缓存并静默重试,导致 Nginx 日志始终显示 "ok";需在最靠近用户的代理层开启 $request_completion 记录
- HTTP/2 流复用会影响判断:单个 TCP 连接承载多个流时,某一流中断不会关闭整个连接,$request_completion 仍能准确反映该流的完成状态
- 小文件可能难以区分:极短请求(如几 KB)在网络层几乎瞬间完成,即使用户快速关闭,Nginx 也可能已写完并记为 "ok"










