Nginx中gzip压缩与缓存绕过共存导致流式接口卡顿,本质是proxy_buffering开启时gzip攒包压缩阻塞分块传输;需验证Content-Encoding、关闭gzip或proxy_buffering、精准配置gzip_types并添加调试响应头定位问题。

缓存绕过与 gzip 压缩共存异常,本质是 Nginx 在启用 gzip 的同时又开启 proxy_buffering 或未正确处理流式响应,导致“本该逐块转发”的数据被攒起来压缩后再发——结果就是客户端收不到实时 chunk,流式接口卡住、延迟飙升甚至超时。
确认是否真由 gzip + 缓存绕过组合引发
别急着改配置。先做两个关键验证:
- 用
curl -H "Accept-Encoding: gzip" -v http://your-domain/api/stream查看响应头中是否有Content-Encoding: gzip,且响应体是否完整返回(而非分块);再对比去掉Accept-Encoding头的结果,看是否只有加 gzip 时才卡住 - 临时关闭 Nginx 的 gzip:在对应
location块里加gzip off;,同时保留proxy_cache_bypass 1; proxy_no_cache 1;,重试流式请求。若恢复正常,基本锁定是 gzip 干扰
检查 proxy_buffering 和 gzip 的协同行为
Nginx 默认开启 proxy_buffering on,它会等上游响应结束才开始 gzip 压缩和转发。这对普通页面没问题,但对流式接口就是致命阻塞:
- 必须显式关闭缓冲:
proxy_buffering off;(注意:仅对需要流式的 location 生效) - 确保
gzip_vary on;已启用,否则某些客户端可能因 Vary 头缺失而复用错误的压缩缓存 - 避免在流式路径上使用
gzip_static on;,它只服务预压缩文件,不参与动态流式压缩
绕过缓存时仍被 gzip 拦截的典型误配
很多人以为加了 proxy_no_cache 1 就万事大吉,但 gzip 不看这个——它只认响应内容和请求头。常见陷阱有:
-
gzip_types配置太宽泛,比如包含application/json或text/event-stream,而流式接口恰好返回这些 MIME 类型 - 没限制 gzip 作用范围,应在流式 location 中单独控制:
gzip_types text/event-stream application/x-ndjson;,其他类型一律不压 - 后端已禁用 gzip(如 Spring Boot 设为
server.compression.enabled=false),但 Nginx 又自己启了 gzip,造成双重压缩或缓冲冲突
验证链路各环节是否真正“不缓存也不压缩”
加一个调试用的响应头,让每一步都可追溯:
- 在 Nginx 的流式 location 中加:
add_header X-Proxy-Bypass $proxy_bypass;和add_header X-Gzip-Status $gzip_ratio; - 用 curl 看这两个头:若
X-Proxy-Bypass是空或 0,说明缓存没真正绕过;若X-Gzip-Status有数值(如 1.23),说明 gzip 生效了——这时就要结合前面几项收紧配置 - 同时检查后端是否返回了
Vary: Accept-Encoding,没有的话 Nginx 可能复用非 gzip 缓存,导致错乱











