搜尋抓取

蜘蛛第二次打開同一頁:304、ETag 與 Last-Modified 的取舍

蜘蛛會反复回訪同一批 URL,服務器每次都重發整頁是浪費。本文解释條件請求與 304 的协作方式,說明 ETag、Last-Modified 在什么情况下會失效,以及它和 Sitemap 里 lastmod 声明的配合關系,並给出一份可以照着做的检查清單。

搜尋抓取

蜘蛛第二次打開同一頁:304、ETag 與 Last-Modified 的取舍

蜘蛛對一批 URL 的回訪是持續的。第一次抓取拿到完整响應体,之後的每一次,如果服務器仍然把整頁重發一遍,带宽、資料库查询和抓取资源都在做重复功。HTTP 的缓存协商机制正是為這種场景准备的:蜘蛛带着上一次拿到的标记来問“内容變了吗”,服務器可以只回一個 304 Not Modified,不带正文。

條件請求長什么样

蜘蛛第二次訪問时,通常會在請求头里带上两個字段中的一個或两個:

  • If-None-Match:值為上一次响應头里返回的 ETag,相当于内容的指纹。
  • If-Modified-Since:值為上一次响應头里返回的 Last-Modified 時間。

服務器比對之後,要么返回 200 加完整正文,要么返回 304 說明副本還能用。從抓取角度看,後者的成本明顯更低。

304 能省下什么

  • 响應体的传輸量。一個頁面 100KB,一天被回訪十次,一個月就是几十 GB 的差別。
  • 服務端渲染與查询的開销。動態站点的压力往往体現在這里。
  • 抓取资源的占用。不同搜尋引擎對 304 的計費方式不完全相同,但通常都比 200 轻。

需要说清的是,304 只說明“這份内容没變”,它並不等于蜘蛛會因此提高抓取频次,也不等于頁面會被收錄。它是一項成本優化,不是一個可以被拿来“刷”的開關。

什么时候不该回 304

配置不当的时候,304 反而會让蜘蛛長期拿着過期副本。以下场景需要重点排查:

  • 内容變了但 ETag 没變。例如 ETag 寫成了固定字符串、模板版本号或站点统一 ID,那么無论正文怎么改,比對都會命中。
  • 多台机器各算各的 ETag。集群里没有把 ETag 生成規則统一,蜘蛛在 A 机拿到指纹、去 B 机比對,结果永遠是 200,等于白做。
  • 時間字段被截断或时区混乱。Last-Modified 精确到秒,If-Modified-Since 却按天比對,或者服務器时区與生成時間不一致,都會让判断错位。
  • 頁面里带實时時間戳。Last-Modified 每次都變,蜘蛛每次都拿全量,协商机制形同虚设。

和 Sitemap 里 lastmod 的關系

很多人把這两件事分開看,其實它們是一组声明與確認:

  • Sitemap 的 lastmod 是你主動声明“這個 URL 什么时候更新過”。
  • 响應头的 Last-Modified 與 304 是服務器被動確認這個声明。

如果 lastmod 每天在變,服務器却始终回 304,声明就失去了可信度;反過来,正文确實改了,ETag 和 Last-Modified 也要跟着更新,否則蜘蛛會一直沿用舊副本。两邊保持一致,比單方面把時間戳改新更有意义。

一份可以照着做的检查清單

  1. 用命令行带條件头發起一次請求,確認返回碼符合预期:curl -I -H "If-None-Match: <上次的 ETag>" 頁面地址。
  2. 改一次正文,重新請求,確認返回的是 200 而不是 304。
  3. 在多台後端机器上分別請求,對比同一 URL 的 ETag 是否一致。
  4. 在服務器日誌里統計 304 的占比。占比過低說明协商基本没生效,過高則要抽查内容更新後有没有及时變化。
  5. 頁面下线或改版时,確認舊 URL 的缓存标记不會繼續让蜘蛛拿到废弃内容。
304 是用来省成本的,不是用来掩盖變更的。寫死一個永遠不變的 ETag,看似让蜘蛛“少拿点内容”,實际上是让它一直拿着一份過期副本在跑。

把條件請求配好,收益不會立刻体現在抓取量上,但會在服務器负载、日誌里的重复传輸和内容更新的及时性上慢慢顯現。對于頁面數量多、更新频繁的站点,這部分優化的性價比通常高于再去找新的抓取入口。