排查抓取問题时,很多人只盯着源站:狀態碼對不對、HTML 有没有坏、内鏈通不通。但從蜘蛛發出請求到拿到 HTML,中間還隔着缓存與 CDN。這一层如果配置不一致,蜘蛛看到的頁面可能和用戶看到的不同,甚至和它上一次抓到的完全一样。
蜘蛛的請求先落在哪一层
常见鏈路是:蜘蛛 → DNS → CDN 邊缘节点 → 源站。如果邊缘节点上有可用副本,請求不會再回到源站。這意味着源站日誌里根本不會出現這次抓取,而蜘蛛拿到的可能是几小时甚至几天前的版本。只看源站日誌做抓取分析,很容易漏掉這一部分訪問。
命中與回源的区別
- 命中缓存:响應快,源站没有日誌,返回内容取决于副本年龄,响應头里的 Age 可以反映這一点。
- 回源:源站产生日誌,返回目前版本,但延迟更高、资源消耗更大。
- 回源失敗:可能返回 5xx,也可能被缓存下来,在一段時間内持續影响抓取。
几類容易踩到的不一致
缓存時間设得過長
HTML 文档如果被設定了很長的 s-maxage 或 max-age,内容更新後邊缘节点仍返回舊版。蜘蛛再訪时看到的内容没變化,自然不會判断為更新過的頁面。動態頁面通常更适合短缓存加回源校驗,長缓存留给長期不變的资源。
缓存键把蜘蛛和用戶分開了
有些配置會按 User-Agent、Cookie 或设备類型区分缓存。如果蜘蛛的 UA 命中了另一份副本,你看到的頁面和它看到的可能不是同一份。响應里的 Vary 头能反映這類分歧,排查时要留意。缓存键分得越细,副本越多,不一致的概率也越高。
回源错誤被当成正常内容缓存
源站短暂 5xx 或超时,如果缓存規則把错誤响應也存了下来,蜘蛛接下来一段時間會持續拿到错誤结果。表現為源站已经恢复,抓取却仍然失敗。這類問题往往要等缓存過期才自行消失。
JS、CSS 被缓存层額外拦截
部分站点在 CDN 上對静態资源和脚本做了額外限制,蜘蛛拿不到完整的渲染资源,看到的頁面结构與實际不符。這類情况常常表現為抓取正常,但内容不完整。
用蜘蛛的视角做一次自查
- 用蜘蛛的 User-Agent 請求關键 URL,對比與浏览器請求返回的 HTML 是否一致。
- 查看响應头中的 Age、Cache-Control、X-Cache、CF-Cache-Status 等字段,確認是命中還是回源。
- 把源站日誌和 CDN 日誌對一遍,找出只有 CDN 有记錄、源站没有的抓取請求。
- 對同一 URL 连續請求两次,观察第二次是否返回同一份副本,判断缓存颗粒度。
- 在内容更新後立刻用蜘蛛 UA 請求一次,確認拿到的是新版本而不是舊副本。
缓存层與抓取稳定性的關系
缓存命中率下降时,回源請求會成倍增加,源站压力上升,超时和 5xx 的概率也随之變大。蜘蛛遇到连續的失敗响應會放慢节奏,短時間内就不再频繁回訪。所以缓存配置不只是性能话题,它間接决定了服務器能不能稳住抓取流量。
内容更新之後可以做的事
- 更新重要頁面後,主動刷新對應 URL 的缓存,而不是等 TTL 自然到期。
- 给 HTML 設定較短的缓存時間,把長缓存留给图片、字体這類不常變的资源。
- 缓存键尽量简單,避免按 UA 分叉出多份 HTML 副本。
- 让回源错誤不進入缓存,或者把错誤响應的缓存時間设得极短。
- 服務器压力大的时候观察回源比例,命中率下降往往先于抓取異常出現。
缓存不是抓取優化的技巧,而是抓取鏈路上的一环。它决定了蜘蛛實际拿到什么,而不是你希望它拿到什么。
蜘蛛看到的頁面是整條鏈路末端的结果,源站只是其中一段。把 CDN、反向代理和源站三處的返回版本對一遍,很多“抓取正常但内容不對”的問题會變得容易解释,也更容易定位到具体该改哪一层。