nginx原生不记录压缩前响应体大小,需通过后端添加x-orig-size等自定义响应头,并用$sent_http_x_orig_size在日志中捕获以实现压缩前后体积对比。

Nginx 默认的 $bytes_sent 和 $body_bytes_sent 记录的是响应体发送给客户端的**实际字节数**(即压缩后、含 HTTP 头以外的响应体大小),但它们本身不区分是否启用压缩,也无法直接反映压缩前原始响应体大小。
关键点:Nginx 原生不记录压缩前体积
Nginx 不像 Apache 那样提供内置变量(如 %I / %O)来分别记录请求/响应原始体积。它没有类似 $bytes_sent_uncompressed 的变量。因此,要实现“压缩前后数据体积对比”,需借助外部手段或模块扩展。
可行方案一:使用第三方模块 ngx_http_log_module(需编译)
社区有补丁版日志模块(如基于 OpenResty 生态的 lua-resty-logger-socket 或自定义 C 模块)可注入压缩前大小。但更实用的是:
- 在应用层(如 PHP/Python/Node.js)生成响应时,提前计算并设置响应头,例如:
X-Orig-Size: 12480 - 在 Nginx 中用
$sent_http_x_orig_size捕获该值,并写入日志:
log_format compare '$remote_addr - $remote_user [$time_local] '
"\"$request\" $status $bytes_sent $sent_http_x_orig_size";
可行方案二:用 Lua + ngx_http_lua_module(推荐)
若已启用 ngx_http_lua_module(常见于 OpenResty),可在响应结束前获取原始响应体长度:
- 在
body_filter_by_lua_block中缓存原始 body 大小(需配合set_by_lua_block或共享内存) - 更简单方式:在应用返回响应时,由后端主动写入
X-Response-Size(未压缩)和X-Sent-Size(实际发送),Nginx 日志直接引用:
log_format compress_log
'"$request" $status $sent_http_x_response_size $sent_http_x_sent_size $bytes_sent';
验证压缩是否生效的辅助方法
即使无法精确记录原始体积,也可通过以下变量交叉判断压缩效果:
-
$sent_http_content_encoding:值为 gzip 或 br 表示启用了对应压缩 -
$sent_http_content_length:响应头中声明的长度(可能被压缩中间件改写,不一定可靠) -
$bytes_sent:实际发出的响应总字节数(含压缩后响应体,不含响应头) -
$body_bytes_sent:等同于$bytes_sent,仅当响应体存在时有效
例如,同一接口开启 gzip 后,$bytes_sent 显著下降且 $sent_http_content_encoding 出现 gzip,即可确认压缩生效。
不复杂但容易忽略:真正需要对比压缩率时,最稳妥的方式仍是后端参与——由业务代码在生成响应前计算原始内容长度,并通过自定义响应头透出。Nginx 日志负责采集和落地,而非承担内容分析职责。











