必须使用 $bytes_sent 变量,它表示实际发送给客户端的总字节数,包括响应状态行、所有首部及响应体,不包含请求数据和网络协议开销。

要在 Nginx 日志中准确记录包含 HTTP 响应首部(headers)在内的完整物理传输字节数,必须使用 $bytes_sent 变量,并确保日志格式配置正确、Nginx 版本支持且无缓冲干扰。
确认 $bytes_sent 的语义符合需求
$bytes_sent 是 Nginx 内置变量,表示**实际发送给客户端的总字节数**,包括:
- HTTP 响应状态行(如
HTTP/1.1 200 OK) - 所有响应首部字段(
Content-Type、Server、Content-Length等) - 响应体(body)内容
- 不包含请求数据,也不含 TCP/IP 协议开销(如 TCP 头、TLS 握手等)
它与 $body_bytes_sent(仅响应体)有本质区别——后者不计入首部,因此监控带宽或调试传输总量时必须用 $bytes_sent。
在 log_format 中显式定义并引用 $bytes_sent
在 http 块中定义自定义日志格式,例如:
"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent"';
然后在 server 或 location 块中启用:
注意:变量名必须写为 $bytes_sent(下划线是合法字符),不能写成 $bytes-sent 或漏掉美元符。
避免 gzip 或代理缓冲导致数值失真
以下情况会使 $bytes_sent 小于预期(尤其首部字节数被低估):
-
gzip on开启后,若响应被压缩,$bytes_sent记录的是压缩后总大小(含压缩后的首部和 body),这反而是真实网络传输量,通常正是你需要的 - 使用
proxy_buffering on(默认开启)时,Nginx 可能合并多个小响应包,但$bytes_sent仍统计最终发出的总字节数,不受影响 - 真正需警惕的是
chunked transfer-encoding流式响应:只要响应完成(连接关闭或 EOS 到达),$bytes_sent就准确;但若连接异常中断,该值可能小于理论值(此时 Nginx 会记录为 0 或部分值)
验证是否生效及排查常见问题
执行一次简单请求并检查日志输出:
curl -I http://localhost/观察 access.log 中对应行的 $bytes_sent 字段是否为非零整数(如 427)。若始终为 0,请检查:
- 是否误用了
$body_bytes_sent - 日志格式未在
access_log指令中实际引用 - Nginx 配置未重载:
nginx -s reload - 请求被拒绝(如 404、403)时,部分版本早期可能不记录
$bytes_sent,建议用 200 响应测试











