$request_completion无法精准识别用户主动中止下载,因其failed状态包含超时、断连等多种原因;需结合$bytes_sent、$status等变量交叉判断,并推荐前端埋点+后端心跳方案实现准确定位。

直接看 $request_completion 变量本身并不能精准标记“用户中止下载”的请求——它只区分请求是否被 Nginx 正常完成(OK)或异常终止(FAILED),而 FAILED 包含超时、后端断连、客户端主动关闭等多种原因,无法单独识别“用户点击暂停/关闭下载窗口”这类行为。
理解 $request_completion 的实际含义
该变量是 Nginx 内置变量,取值只有两个:
- OK:请求被完整处理并成功返回响应体(无论状态码是 200、304 还是 4xx/5xx,只要响应头+体发完就算 OK)
- FAILED:连接在响应发送过程中被意外中断(如客户端断开、超时、worker crash 等),Nginx 未能完成响应发送
注意:FAILED 不等于“用户点了取消”。比如用户下载到 80% 时关掉浏览器,Nginx 通常记录为 FAILED;但若后端 PHP 脚本卡死导致超时,也会记为 FAILED——两者在日志里无法区分。
用 $status + $bytes_sent + $request_completion 组合判断可疑中止
单靠 $request_completion 不够,需结合其他变量交叉分析。重点关注大文件(如 >1MB)的响应:
- 当
$request_completion = FAILED且$bytes_sent > 0且$bytes_sent → 很可能是用户中途断开(未发完就断) - 同时检查
$status:若为206(范围请求)且$bytes_sent明显小于预期分块大小,也指向主动中断 - Nginx 日志格式示例:
log_format download_log '$time_iso8601 $remote_addr "$request" $status $bytes_sent $request_completion $http_range';
配合 access_log 条件记录,减少噪音
避免把所有 FAILED 都记为“用户中止”,可用 map + if(在 log 指令中)做轻量过滤:
map $request_completion $is_aborted_download {
default "";
FAILED "$bytes_sent";
}
log_format abort_log '$time_iso8601 $uri $is_aborted_download $http_user_agent';
access_log /var/log/nginx/aborted-downloads.log abort_log if=$is_aborted_download;
这样只记录 FAILED 且有数据发出的请求,排除了纯连接失败($bytes_sent=0)的情况。
更可靠的替代方案:前端埋点 + 后端心跳
真正想 100% 确认用户主动中止,Nginx 层做不到。推荐组合方案:
- 前端 JS 监听
beforeunload或visibilitychange,在用户关闭页面/切走前上报下载 ID 和已接收字节数 - 服务端生成带唯一 trace_id 的下载链接,并记录文件大小;收到前端上报后比对已传字节,确认是否提前终止
- Nginx 日志作为辅助(用
$request_completion发现异常链路),而非唯一依据
这样既能准确定位真实中止行为,又能回溯具体用户、设备、网络环境等上下文。











