应使用 $bytes_sent 变量记录含响应头的实际传输字节数,配合自定义日志格式包含 $status 和 $bytes_sent,确保 nginx ≥1.3.12,可准确分析各状态码下的真实带宽消耗。

要在 Nginx 日志中准确记录包含响应头在内的**实际传输字节数**(即网络层真正发出的总字节数),并同时关联状态码以分析不同状态下的真实带宽消耗,关键在于:使用 $bytes_sent(非 $body_bytes_sent),配合自定义日志格式,并确保 Nginx 版本支持该变量的完整语义(1.3.12+ 稳定可用)。
确认 $bytes_sent 的真实含义
$bytes_sent 表示 Nginx 向客户端**实际发送的总字节数**,包括响应头(如 HTTP/1.1 200 OK、Content-Type、Content-Length 等所有 header 字节)和响应体(body)字节之和。它不同于 $body_bytes_sent(仅 body),也不同于 $request_length(请求总长)。这是实现“绝对传输体积”监控的唯一可靠变量。
配置含状态码与 $bytes_sent 的自定义日志格式
在 http 或 server 块中定义日志格式,显式包含 $status 和 $bytes_sent:
log_format full_with_bytes '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time';然后在 access_log 指令中启用该格式:
access_log /var/log/nginx/access.log full_with_bytes;
✅ 日志行示例:192.168.1.100 - - [10/Jul/2024:14:22:35 +0800] "GET /api/v1/users HTTP/1.1" 200 1248 "https://example.com/" "curl/8.6.0" 0.023 0.021
其中 200 是状态码,1248 是含 header 的真实发送字节数(可验证:用 curl -v 查看响应头大小 + body 大小 ≈ 1248)。
验证与排查常见偏差
-
gzip 压缩影响已自动计入:Nginx 在启用
gzip on后,$bytes_sent记录的是压缩后实际发送的字节数(含压缩后的 header + body),无需额外处理; -
连接复用(keepalive)不干扰单次计数:每个请求独立记录,即使复用 TCP 连接,
$bytes_sent仍精确对应本次响应的发送量; -
注意 304 响应的特殊性:304 响应无 body,但仍有响应头(如
Date,Connection,ETag),$bytes_sent会如实记录这些 header 字节数(通常 100–300 字节),可用于识别缓存命中效率; - 避免使用 $body_bytes_sent 替代:它不包含 header,对 204/304/404 等无 body 响应会记为 0,完全丢失 header 开销信息。
进阶联动分析建议
将日志接入 ELK 或 Prometheus + nginxlog-exporter 后,可构建如下监控维度:
- 按
$status分组,统计平均$bytes_sent:识别 500 错误是否伴随异常大响应(如堆栈全量返回); - 计算
$bytes_sent / $body_bytes_sent比值:评估 header 膨胀程度(如大量自定义 header 导致比值 > 1.2); - 结合
$request_time计算真实吞吐(Bps):定位慢请求是否因传输体积过大而非后端延迟; - 过滤
$status ~ "^5"且$bytes_sent > 10000:告警大体积错误响应,防止敏感信息泄露或带宽滥用。











