DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
PanstarCloud:部署应用,接入 AI,云服务器与 AI 网关
OnlineSIM:在线接收短信,虚拟号码租用

Spring 已解压 GZIP 却留下压缩头:核对编码值大小写

Spring JdkClientHttpRequestFactory 开启压缩时,GZIP 等混合大小写值可成功解压却保留旧编码和长度头。7.0.10 两处比较仍不同,须让实际正文与转发元数据一致。

JDK HTTP 客户端已经把 gzip 正文解开,响应头却还写着 Content-Encoding: GZIP,Content-Length 也是压缩数据的字节数。若 Spring 的 JdkClientHttpRequestFactory 开启了自动压缩处理,要对比编码值大小写,而不只是继续排查解压失败。

Spring Framework 7.0.6、7.0.9 的具体对照中,小写 gzip、deflate 会在解压后移除两项旧头;大写或混合大小写则留下旧头,正文仍能正确解压。7.0.10 正式代码也保留了解码选择与响应头清理的大小写差异。

正文解码与头部清理用了不同判断

解压处理先把 Content-Encoding 转成小写,再选择支持的解码器。清理响应头时却直接用原值查小写集合。GZIP 能进入解压分支,随后又不能通过清理条件,最终暴露出“解压后的流加压缩时的元数据”。

如果下游继续按 GZIP 再解压,或按旧长度处理新正文,就可能出现后续错误。先确认自动压缩确实开启、正文是否已经解开,以及头部来自哪一层。服务端原本没压缩却错误声明 gzip、重复代理修改头部,以及多个编码串联,都不是这条单一编码大小写路径。

这里的大小写指值,不是 Content-Encoding 这个头名称。单纯把头名称改成小写,不能修正清理代码对编码值的比较。

能控制响应方时,统一已确认的编码值

对于自己控制且确实输出单层 gzip 或 deflate 的服务,可让其使用对应的小写编码值,并保留真实压缩体和长度。它没有改变压缩算法,只是避开受影响客户端清理时的大小写分支。必须同时验证正文确实使用所声明的编码,不能把任意上游值强改成 gzip。

如果应用读取解压后的业务数据,再为下游生成新响应,不要把上游的 Content-Encoding 和 Content-Length 原样复制给新正文。按本应用的响应构造流程生成对应元数据;其他必要头仍按既有转发规则处理,不应一次删掉所有响应头。

这项调整只适用于已经确认自动解压完成的路径。一般代理也可能需要透传原压缩字节,这时就应保留匹配的编码与长度。把所有响应的压缩头无条件删除,会破坏正常透传。

不能控制服务端且需要暂时避开自动解压时,可评估沿原客户端配置禁用这项处理,并请求不压缩的响应;但服务端是否遵循请求、实际响应是否仍有编码,都必须核对。不能一边关闭自动处理,一边仍把压缩字节当普通 JSON 读取。

验收用同一正文分别覆盖 gzip/GZIP/GzIp 和 deflate/DEFLATE 等值,比较解码后的字节与对下游暴露的头是否一致,并回查原来不压缩和正常透传的路径。后续采用正式 Spring 更新时,检查解码与头部清理两处比较是否一致,并用同一组输入复验。