Nginx 1.24 上同时装了 brotli 模块并保留 gzip on,日志里蜘蛛请求的响应码是 200,但内容长度只有正常的三分之一,快照里正文是乱码,浏览器访问却一切正常。

一开始怀疑是「压缩级别设成 11,大页面压缩超时后输出被截断」,查了一圈,方向不对。

真正麻烦的地方在于,几个原因的现象几乎一样。brotli 在 gzip 之前生效,Content-Encoding 被写了两遍。少数情况下是上游 CDN 又把 br 转成 gzip,字符集和编码对不上。

不容易想到的是,Vary 头里只写了 Accept-Encoding 之外的值,缓存串了版本。

先看响应头里的编码声明

curl -sI -H 'Accept-Encoding: br,gzip' https://www.example.com/ | grep -i -E 'content-encoding|vary|content-length'

接着分别只用一种编码取正文长度

curl -s -H 'Accept-Encoding: gzip' https://www.example.com/ | wc -c

再往下在 Nginx 里只保留一种压缩

brotli on;
gzip off;

剩下的就是确认压缩级别不会拖到超时

brotli_comp_level 5;

恢复的判定其实很直接。响应头里只剩一个 Content-Encoding,正文长度恢复到正常值,快照和浏览器渲染一致。

补一句。同时开两种压缩模块时顺序很关键,宁可只留一种,也不要把编码声明交给两层去拼。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。

作者 9823189