搜索蜘蛛在抓取页面时,拿到的不只是 HTML 文本,还包括一组响应头。其中 Content-Encoding 与 Content-Length 这两个字段,直接决定了蜘蛛能否顺利解出页面内容。压缩协商一旦出现偏差,表现往往不是明显的 5xx,而是“抓到了但内容不对”或者“抓一半就断”,排查起来比较绕。
压缩协商的正常流程
请求方在请求头里声明自己支持的压缩方式,例如 Accept-Encoding: gzip, deflate, br。服务器挑其中一种,把响应体压缩后返回,同时在响应头里用 Content-Encoding 说明用了哪种算法,用 Content-Length 说明压缩后的字节数(注意是压缩后的长度,不是原始长度)。中间的 CDN 或反向代理如果不透传这些头,就可能出现声明与实际不一致。
几类典型异常
Content-Encoding 与实际内容不符
服务器声明 gzip,但响应体其实是明文,或者经过了两层压缩(CDN 压了一次、源站又压了一次),蜘蛛按声明解压就会失败,最终拿到空内容或乱码。多级代理叠加压缩是常见诱因。
Content-Length 与实际字节数不一致
头部写的是 20000,实际只传了 8000,蜘蛛按长度等待剩余数据,超时后放弃,表现为抓取中断;反过来,实际传输超过声明长度,多余部分可能被截断或被视为协议错误。动态压缩、流式输出时最容易出现这种偏差。
Vary 缺失导致的缓存串味
如果同一 URL 对不同 Accept-Encoding 返回不同内容,而响应里没有 Vary: Accept-Encoding,CDN 可能把压缩版缓存下来发给不支持该算法的请求方,或者把明文版发给期望压缩的请求方。表现是同一地址时好时坏,很难复现。
排查步骤
- 用带 Accept-Encoding 的请求直接拉取目标 URL,对比源站直连与经过 CDN 后的响应头差异。
- 检查 Content-Encoding、Content-Length 是否同时存在且自洽,有条件时用原始字节数核对一次。
- 确认压缩层级,看源站与 CDN 是否重复启用压缩,只保留一层。
- 检查 Vary 头是否包含 Accept-Encoding,避免缓存串味。
- 对比同一 URL 在压缩与非压缩请求下的正文内容,两者应当基本一致。
- 查看抓取日志中该路径的状态码与响应体大小,判断问题集中在某类资源还是全站。
调整与验证
修复方向通常是:关闭重复压缩、补齐 Vary、让 Content-Length 与实际传输字节严格一致,或者对大页面改用分块传输并去掉固定的 Content-Length。改完后不要只看一次请求,最好在不同时间段、不同出口各验证几次,确认头部表现稳定。
压缩协商这类问题不会让页面彻底无法访问,人工浏览时几乎无感,但对自动抓取的影响是持续性的。把它纳入服务器响应头的例行巡检,比事后反复猜测某些 URL 为何抓取异常更省事。
小结:抓取链路上任何一个环节对响应头的改写,都可能让蜘蛛“收到了却读不懂”。把 Content-Encoding、Content-Length、Vary 三者放在一起交叉验证,通常能较快锁定问题位置。