搜尋抓取

缓存头與 304:蜘蛛重复訪問时,服務器该怎么回應

蜘蛛第二次、第三次訪問同一個 URL 时,往往带着條件請求头。服務器返回全量内容還是 304,取决于 Last-Modified、ETag 與 Cache-Control 的設定。本文梳理這三個头各自管什么、CDN 邊缘缓存如何影响蜘蛛看到的版本,以及日誌與缓存记錄该怎么並排核對。

搜尋抓取

缓存头與 304:蜘蛛重复訪問时,服務器该怎么回應

蜘蛛第一次抓走一個 URL 之後,通常還會回来。第二次、第三次它带着缓存校驗信息来,服務器回什么,會直接影响抓取节奏和带宽消耗。這块内容在日誌里不如 404、500 顯眼,容易被忽略,但积累起来對抓取效率的影响並不小。

條件請求:蜘蛛不是每次都從零開始

支持條件請求的爬虫在重新抓取时,會带上 If-Modified-SinceIf-None-Match。服務器判断頁面没有變化,就返回 304 並给出空响應体,蜘蛛據此知道内容照舊,可以复用已有版本。响應体變小,抓一個 URL 的成本降低,同样的抓取预算能走更多地址。

  • If-Modified-Since 依赖响應里给出的 Last-Modified 头
  • If-None-Match 依赖 ETag
  • 两者可以同时存在,服務器按自己的優先級判断,但结果要一致

三個头分別管什么

Cache-Control

它主要面向浏览器和中間缓存,蜘蛛本身對 max-age 的依赖有限,但 CDN 邊缘节点會照它执行。如果把 HTML 设成很長的 max-age,邊缘节点可能長期不回源,蜘蛛每次拿到的都是舊内容,更新传不出去。常见做法是 HTML 走短缓存或协商缓存,静態资源長缓存。

ETag

ETag 是资源版本的指纹。要保證同一份内容在不同节点上生成的 ETag 一致,否則請求在邊缘节点之間切換时,可能被反复判定為已變更,回源和全量响應都會變多。有站点干脆用内容哈希而不是時間戳来生成。

Last-Modified

時間戳要真實反映内容變化。有些程序每次渲染都刷新這個值,蜘蛛每次訪問都被判定頁面更新,于是重复下载。頁面實际没變的时候,把它稳定住。

304 是不是好事

一般情况下是的,但有两個前提。一是頁面内容确實没變;二是 304 不會掩盖真實問题——比如某次模板报错,頁面被降級成空壳,若仍返回 304,蜘蛛會繼續認為舊版本有效。另一類情况是新頁面刚上线,服務器错誤地返回 304,蜘蛛可能延迟發現。核對时把 200 與 304 的比例放進更新時間线里看,比只看總量更有意义。

CDN 與回源

蜘蛛的出口 IP 分散,命中不同邊缘节点时,看到的缓存狀態可能不同。抓取日誌和 CDN 日誌要並排看:哪些請求命中邊缘、哪些回源、回源後的狀態碼是什么。如果某類 URL 命中率极低,通常是缓存键设計的問题,常见原因是键里带了 Cookie 或跟踪參數,把同一份内容拆成了很多份。

  • 缓存键要不要包含查询參數,按參數是否影响内容决定
  • 不要给蜘蛛的 UA 單獨開一條绕過缓存的規則,容易让缓存形同虚设
  • 回源频繁的 URL 類型,優先排查缓存键與 Vary 头
缓存策略的目标不是單纯省流量,而是让蜘蛛每次拿到准确的目前版本,並且不為没變化的内容重复付費。

核對顺序

  1. 在日誌里筛出同一個 URL 的多次訪問,观察响應碼與响應体大小
  2. 抽样几個更新過的頁面,確認 Last-Modified 與 ETag 随内容變化
  3. 检查 HTML 的 Cache-Control,避免過長的 max-age 卡住邊缘节点
  4. 對比 CDN 命中與回源记錄,找出反复回源的 URL 類型
  5. 手動發一次條件請求,確認内容未變时服務器返回 304

這些检查不需要一次做完。從訪問量最高的一批 URL 開始,逐步往外扩,改動一次就回到日誌里驗證一次,比一次性推翻整套缓存配置稳妥得多。