报错是这么冒出来的。图片站从 nginx 1.18 升到 1.24,顺手打开了 gzip_static on,脚本给 /uploads 下的 jpg 批量生成了同名 .gz。升级后日志里图片请求状态码都是 200,body_bytes_sent 只有 20 到 40 字节,百度图片搜索的收录一周里从四万掉到三百多。重启过 nginx,也清过 CDN,现象没变。

中间走过弯路,把「响应头带了 Content-Encoding: gzip 但正文没有压缩数据,客户端直接判解析失败」当成主因,改完现象没变。

真正麻烦的地方在于,几个原因的现象几乎一样。gzip_static 命中优先返回 .gz,而那批 .gz 是脚本失败留下的 0 字节空文件。也可能是.gz 的属主是 root 且权限 600,worker 进程读不到,又没有回退到原图。

还有一种情况,图片目录本来不该开静态压缩,Content-Length 和实际内容对不上。

上来先列出 .gz 文件的大小分布,找出 0 字节的那批

find /data/uploads -name '*.gz' -size -1k | head -20

再往下对比同一张图原图和 .gz 的文件大小与权限

ls -l /data/uploads/2026/10/cover.jpg /data/uploads/2026/10/cover.jpg.gz

校验 gz 文件本身是否完整

gunzip -t /data/uploads/2026/10/cover.jpg.gz

只对文本类型开静态压缩,图片目录单独关掉

location ~* \.(jpg|png|webp)$ { gzip_static off; }

恢复的判定其实很直接。清掉空文件并关掉图片目录的 gzip_static 后,同一张图的 body_bytes_sent 回到正常大小,客户端能完整解码,三天后图片收录开始回升。

gzip_static 不会判断 .gz 是否比原文件新,源图换了而压缩包没重生成,蜘蛛拿到的还是旧图。监控比日志更早给出信号,事后回看经常能提前半小时发现异常。

作者 9823189