
开启 CDN 压缩后,响应体积没有变小,甚至出现下载文件损坏、浏览器提示解压失败或 API 返回乱码,通常不是“压缩算法突然失效”。更常见的原因是缓存中保存了错误的编码版本、源站和 CDN 重复压缩,或者请求与响应的变体没有正确区分。
排查时不要只看 CDN 控制台里的压缩开关。要把客户端实际收到的响应、CDN 到源站的请求、缓存键以及源站返回的 Content-Encoding 放在同一条链路里比较。本文以公开的文本、CSS、JavaScript 和 JSON 响应为例,压缩策略与可缓存范围仍需以实际 CDN 配置为准。
先确认异常发生在哪一段
分别保存三组信息:客户端收到的响应头和正文、CDN 回源请求的响应头、源站直接响应的原始内容。重点记录 Content-Encoding、Content-Length、Transfer-Encoding、Vary、Cache-Control、ETag 和缓存状态。不要在生产环境用带随机参数的大文件反复制造未命中。
使用同一个 URL,分别发送带和不带 Accept-Encoding 的请求。比较时同时看正文摘要和解压后的内容,不要直接拿压缩字节与未压缩字节比较大小。curl 是否自动解压也取决于命令参数,测试记录中应写明是否使用了 --compressed。
curl -sS --compressed \ -D response-compressed.headers -o response-compressed.body \ 'https://cdn.example.com/assets/app.js' curl -sS \ -H 'Accept-Encoding:' \ -D response-plain.headers -o response-plain.body \ 'https://cdn.example.com/assets/app.js' sha256sum response-compressed.body response-plain.body
第二个请求只是示例,不同 CDN 对空的 Accept-Encoding、默认编码和缓存键处理可能不同。先确认测试对象允许这样读取,并在结果中记录实际响应头。
Content-Encoding 和缓存变体必须一致
Content-Encoding: gzip 或 br 表示响应正文经过了相应编码。客户端会按照这个声明解码;如果正文已经压缩过却没有正确声明,或者声明与实际编码不符,浏览器和 API 客户端可能报解压错误。
同一 URL 可能需要按 Accept-Encoding 生成不同响应。响应通常应通过 Vary: Accept-Encoding 表示这一点,但是否由 CDN 自动处理、是否把它纳入缓存键,取决于平台和缓存规则。不能看到一个 Vary 头就假设所有边缘节点都已经按相同方式存储对象。
核对以下组合:
客户端请求的
Accept-Encoding;CDN 命中的缓存对象及其缓存键;
CDN 回源时发送的请求头;
源站返回的
Content-Encoding与Vary;CDN 发给客户端的正文是否经历了再次编码。
认证页面、个性化 JSON 和带用户状态的响应更需要谨慎。为了提高命中率而忽略会影响响应内容的请求头,可能造成内容串用。
重复压缩比压缩率不高更危险
常见错误链路是:源站已经返回 gzip,CDN 没有识别或正确保留该状态,又对正文执行一次压缩。客户端收到的内容可能多了一层编码,但响应头只有一层 Content-Encoding;也可能 CDN 修改了长度或校验相关头,却没有同步正文。
检查源站和 CDN 的压缩职责,只保留一个明确的压缩边界。源站已经压缩的资源,通常应让 CDN 直接传递,或按服务商支持的方式解压后重新编码,但不要让两个环节无条件重复处理。静态 .gz、.br 文件和普通未压缩文件也不要仅凭扩展名判断编码状态。
可以用解码器验证正文层数,但要对测试文件操作。以 gzip 为例:
gzip -t response.body
这个命令只能验证文件是否是合法 gzip 数据,不能证明 HTTP 头、缓存变体或业务内容都正确。对于 Brotli,使用环境中可靠的 brotli 工具进行对应测试,并记录版本。
缓存可能保存了错误版本
如果压缩配置或源站响应头发生变化,旧缓存对象不会自动变成新对象。某些节点已经填充了新版本,另一些节点仍在返回旧的编码版本,就会出现区域性或随机性错误。
把异常按 URL、Accept-Encoding、缓存状态、边缘节点和 Age 分组。不要只刷新 HTML;页面引用的 CSS、JS、字体和 API 也可能有独立的缓存对象。优先对受影响的明确路径执行精确失效,并先确认源站能够稳定返回正确正文。
精确刷新也不能覆盖浏览器缓存、Service Worker 或其他域名。发布记录应保存配置变更时间、失效任务 ID、验证节点和响应头摘要。大范围清缓存会增加回源压力,不能替代对缓存键和编码职责的修复。
为什么压缩后响应可能看起来更大
压缩对短文本、已经压缩过的格式和随机性较高的数据不一定有收益。压缩流本身有头部和字典开销;如果比较的是不同请求的传输层字节,还可能把 TLS、分块传输或统计口径差异混在一起。
图片、视频、归档包和压缩包通常不应再做同样的文本压缩。不要只根据文件后缀决定是否压缩,最好结合 MIME 类型、内容大小和实际响应。对于小响应,设置一个最小压缩阈值可能比强制压缩所有对象更合理,但阈值和压缩级别会影响 CPU 与延迟。
确认“响应变大”时,至少区分:源站对象大小、CDN 到客户端的正文大小、客户端实际接收字节以及账单中的计费字节。它们不是同一个指标。
按顺序修复并验证
先在一个小型公开测试对象上确认源站未重复压缩,响应头与正文相符;再核对 CDN 的压缩规则、缓存键和 Vary 处理;最后只刷新受影响的资源路径。不要在没有回滚配置和测试对象的情况下直接切换全站压缩策略。
验证至少覆盖一个明确支持 gzip 或 Brotli 的客户端、一个不发送 Accept-Encoding 的请求,以及两个不同网络或边缘节点。比较解码后的正文摘要、Content-Encoding、Vary、ETag、响应长度、错误率和源站回源量。
如果是 API 或下载接口,确认客户端是否已经自动解压。客户端自动解压后再把“解压后的正文”当作压缩字节转发,也可能造成二次处理。修改规则时一次只改变一个变量,保留旧配置、失效范围和回退步骤。
参考资料
资料核验日期:2026 年 11 月 10 日。本文给出的命令为受控读取与文件校验示例,不代表已在读者的生产环境执行。