蜘蛛池知识

蜘蛛池入口頁的缓存头與 304:蜘蛛回訪时到底讀到了什么

蜘蛛回訪入口頁时,會带上 Last-Modified 和 ETag 来問服務器内容有没有變。缓存头寫得不合适,就容易出現该更新时返回 304、不该抓时反复全量抓取的情况。本文梳理几個常见响應头的含义、日誌里 304 的正确讀法,以及蜘蛛池场景下比較稳妥的配置思路。

蜘蛛池知识

蜘蛛池入口頁的缓存头與 304:蜘蛛回訪时到底讀到了什么

入口頁能不能被蜘蛛稳定抓取,很多时候不取决于内容寫了什么,而取决于服務器怎么回應蜘蛛的每一次回訪。其中最容易忽略的一环,就是 HTTP 缓存相關的响應头,以及由此产生的 304 狀態碼。

蜘蛛回訪不是每次都要讀完頁面

蜘蛛在第二次、第三次訪問同一個 URL 时,通常會带上 If-Modified-Since 或 If-None-Match 請求头,把上次拿到的 Last-Modified 或 ETag 一起送過来。服務器如果判断内容没變,就可以返回 304 Not Modified,不用再传一遍正文。對蜘蛛池這種入口頁數量多、單頁内容變化不频繁的场景,這個机制直接决定了蜘蛛每次回訪要消耗多少带宽和服務器资源。

几個头部各自在表達什么

  • Last-Modified:告诉蜘蛛這個頁面最後一次變化的時間。它不一定等于文件真實修改時間,很多程序會寫成模板渲染時間。
  • ETag:内容的指纹。不同類型服務器生成規則不同,有的按内容哈希,有的還带進程、inode 信息。
  • Cache-Control:主要给浏览器和中間缓存看,但蜘蛛也會參考。max-age 太長时,蜘蛛可能看到的是缓存层里的舊副本。
  • Expires:老式寫法,和 Cache-Control 同时存在时容易被忽略,但不建议两邊寫互相冲突的值。

304 不等于“蜘蛛没来”

很多人在看日誌时,看到大量 304 就以為蜘蛛在敷衍、没有真正抓取。實际上 304 說明蜘蛛来了、問了,並且服務器確認内容没變,這是一次正常的交互。真正需要警惕的是另一種情况:内容明明改了,服務器仍然返回 304,蜘蛛拿到的還是舊版本的判断依據,頁面更新就一直传不出去。

判断入口頁是否被正常回訪,最好把 200、304、404 分開統計,再结合响應時間和抓取频次一起看,單看某一類狀態碼容易得出相反的结论。

蜘蛛池场景里常见的几個坑

  1. 模板统一生成 Last-Modified:每次請求都返回目前時間,蜘蛛每次都觉得内容變了,于是反复全量抓取,白白消耗抓取预算。
  2. ETag 跟着進程變化:多台後端、多次重啟後 ETag 不一致,缓存判断反复失效,回訪时好时坏。
  3. 缓存层與源站狀態碼不一致:CDN 或反向代理返回 304,但源站其實已经更新,蜘蛛拿到的是過期副本。
  4. 對所有入口頁設定超長 max-age:内容更新後,蜘蛛在缓存過期前都讀不到新版本。
  5. 用重定向代替 304:為了“省流量”把回訪跳到別的地址,反而让蜘蛛對 URL 的稳定性产生困惑。

比較稳妥的配置思路

如果入口頁内容會定期更新,建议让 Last-Modified 和實际更新時間保持一致的逻辑,例如由内容的最後編輯時間决定,而不是每次渲染取目前時間。ETag 尽量基于内容生成,不掺入進程或物理路径信息。Cache-Control 可以给一個中等長度的 max-age,同时配合 must-revalidate,让缓存层在内容變化後愿意回源確認。

對于長期不變、只作為連結入口的静態頁,則可以给較長的缓存時間和較少的回訪频率预期,让蜘蛛把更多抓取次數留给真正需要更新的目标頁。具体長度没有统一答案,需要结合入口頁的數量、更新节奏和服務器承载能力来調,先小范围观察日誌里的 200 與 304 比例,再决定是否放宽。

最後提醒一点:缓存头是服務器與蜘蛛之間的“沟通约定”,它影响的是抓取效率,不决定頁面是否會被收錄。把它当成资源優化和抓取节奏管理的一部分,比当成提升效果的開關更實际。