搜尋抓取

缓存协商與 304:减少蜘蛛對同一 URL 的重复下载

蜘蛛對同一個 URL 反复抓取,往往比抓取不足更浪費预算。本文讲清條件請求(If-Modified-Since、If-None-Match)與 304 响應的實际作用,說明哪些頁面适合依赖缓存校驗、哪些内容更新反而會被 304 挡住,以及 Sitemap 的 lastmod 该怎么和缓存头對齐,並给出可落地的驗證方法。

搜尋抓取

缓存协商與 304:减少蜘蛛對同一 URL 的重复下载

蜘蛛抓取站点时,最容易被忽略的浪費不是“抓得少”,而是“抓重复”。同一個 URL 在几周内被反复訪問,服務器每次都把整份 HTML 重新吐一遍,带宽、CPU 和抓取配額都在為此買單。缓存协商(條件請求)正是為這種场景准备的:让蜘蛛問一句“變了没有”,没變就只回一個 304。

蜘蛛為什么會重复訪問同一個 URL

蜘蛛不會完整记住頁面内容,它儲存的是上次抓取的時間、ETag 之類的校驗信息。再次訪問时,它會把這些信息带在請求头里。如果你的服務器不做校驗,直接返回 200 和完整正文,蜘蛛只能重新下载、重新解析。

對更新缓慢的頁面——關于我們、帮助文档、半年前的文章——這類重复下载會占據相当比例。它們不是没有價值,而是没有必要每次都整份重来。

條件請求是怎么工作的

  1. 蜘蛛第一次抓取,服務器在响應头返回 Last-Modified 或 ETag。
  2. 下次抓取时,蜘蛛带上 If-Modified-Since 或 If-None-Match。
  3. 服務器比對後,如果内容没變,返回 304 Not Modified,不带正文。
  4. 如果變了,正常返回 200 與新内容,同时更新校驗标识。

對蜘蛛而言,304 表示“這個 URL 我看過,内容照舊”,這次訪問仍會被记錄,但省掉了下载和解析;對服務器而言,省掉的恰恰是最贵的部分——生成頁面和传輸正文。

什么情况不适合依赖 304

  • 内容确實改了,但 Last-Modified 没更新,例如只改了資料库字段,文件時間没動。蜘蛛會持續拿到 304,看不到更新。
  • 頁面由模板拼装,每次生成的 ETag 都不一样,等于每次都“變了”,304 永遠不會命中。
  • 頁面包含實时資料、评论數或库存,几分钟就變一次,强行 304 反而會让缓存判断失真。

判断标准很简單:這個頁面的“變”是内容层面的,還是渲染层面的。只有内容层面的變化才值得用缓存头表達。

Sitemap 的 lastmod 要和實际對齐

Sitemap 里的 lastmod 與响應头的 Last-Modified 描述的是同一件事的不同侧面,最好保持一致。如果 Sitemap 声明“昨天更新”,而服務器對條件請求返回 304,蜘蛛會收到互相矛盾的信号:要么怀疑 Sitemap 不准确,要么降低對 lastmod 的信任。

反過来,如果内容真的更新了,Sitemap 的 lastmod 却一直不動,蜘蛛也可能按舊的节奏来,更新的發現會變慢。

配置时容易踩的坑

  • CDN 與源站的缓存头不一致,蜘蛛看到的是邊缘节点的响應,源站的校驗信息被覆盖。
  • ETag 里混入了随机值、時間戳或進程 ID,導致同一頁面每次校驗值都不同。
  • 只關注狀態碼,不看日誌里同一 URL 的 200 與 304 比例,改没改,全凭感觉。
  • 把動態參數頁也纳入長期缓存,结果參數變了内容却返回 304。

怎么驗證有没有生效

  1. 用抓取工具或命令行带 If-Modified-Since 請求同一 URL,確認第二次返回 304。
  2. 在服務器日誌里按 URL 統計 200 與 304 的次數,看重复下载是否下降。
  3. 對確認更新過的頁面,驗證服務器是否及时返回 200 與新内容,而不是繼續 304。
缓存协商並不决定蜘蛛要不要抓,它决定的是每次抓取的成本。抓取预算有限时,把重复下载省下来,才等于把机會留给了真正的新 URL。