Nginx自定义日志中记录请求体和响应体大小需选对变量:响应体用$body_bytes_sent(不含响应头),请求体优先用$content_length(取Content-Length头),并按路径启用日志以避免冗余。

在 Nginx 自定义日志格式中加入请求体和响应体大小,关键不是“加变量”这么简单,而是要选对变量、配对启用条件、并明确记录意图——因为 Nginx 不会自动读取或缓存请求体,响应体大小也分“纯内容”和“含头总和”两种含义。
响应体大小:用 $body_bytes_sent,不是 $bytes_sent
记录 API 返回数据量(比如 JSON 字节数),必须用 $body_bytes_sent。它只统计响应体(response body)字节数,不含响应头,稳定可靠。
而 $bytes_sent 包含响应头 + 响应体,Header 长度受 Cookie、自定义字段、代理层数影响大,不适合做接口数据量监控基准。
在 http{} 块中定义日志格式时显式包含该变量:
其中:
-
$body_bytes_sent:单位为字节,值为 0 表示无响应体(如 304、204) -
$status和$body_bytes_sent组合可快速识别异常:200 但 body 为 0(空响应)、或 200 但 body 过大(如 >5MB)
请求体大小:优先用 $content_length,慎用 $request_body
获取原始 POST/PUT 请求体大小,最实用、最轻量的方式是读取请求头中的 Content-Length 字段,对应 Nginx 变量为 $content_length。
它在标准非分块(non-chunked)请求中准确反映客户端声明的 body 字节数,无需额外缓冲或磁盘操作,零性能开销。
若需真正捕获原始请求体内容(例如调试签名或参数),才考虑 $request_body,但必须满足两个前提:
- 在对应
server或location块中启用:client_body_in_single_buffer on;或至少client_body_buffer_size足够大 - 且不能与
proxy_pass同时使用(Nginx 会清空 body);如需透传 body,得改用proxy_buffering off+proxy_pass_request_body on
日常监控请求大小,推荐直接加 $content_length 到日志格式中:
按路径启用日志,避免干扰静态资源
不要全局开启带 body 相关字段的日志,应在具体业务路径下单独配置,例如仅对 API 或上传接口生效:
location /api/ {access_log /var/log/nginx/api_access.log api_log;
}
location /upload/ {
access_log /var/log/nginx/upload.log upload_log;
}
这样既保证关键路径日志完整,又避免图片、JS、CSS 等静态资源日志膨胀,也规避了 $request_body 对非 POST 请求的无效占用。
注意权限与缓冲配套,否则字段可能恒为 0 或报错
$content_length 在绝大多数情况下都能正常输出;但 $body_bytes_sent 若始终为 0,常见原因有:
- 后端服务未真正返回响应体(如提前 close、返回空 response)
- Nginx 被配置为
subrequest或error_page重定向,导致主请求体未发出 - 启用了
gzip_vary on但未配gzip on,部分场景触发异常流控
同时确保 client_max_body_size 在对应 location 中已合理设置,否则大请求被 413 拦截,根本不会走到日志写入阶段。


















