搜尋抓取

让蜘蛛少下一遍整頁:304 與條件請求的配置思路

蜘蛛會反复請求同一批 URL,如果服務器每次都重發完整頁面,带宽和抓取額度都會被消耗掉。條件請求通過 If-Modified-Since 與 If-None-Match 判断内容是否變化,未變时返回 304,只回响應头不回正文。本文說明它的工作方式、常见失效情形、日誌核對方法與配置要点。

搜尋抓取

让蜘蛛少下一遍整頁:304 與條件請求的配置思路

為什么同一個 URL 會被反复抓取

蜘蛛不是抓一次就记住頁面内容。為了確認頁面有没有更新,它會在一段時間後再次請求同一批 URL。如果一個站点有几萬個頁面,蜘蛛每天来几轮,服務器就要把這批頁面重复發送好几遍,而真正發生變化的可能只是一小部分,剩下的带宽和响應時間都花在了没變的内容上。

减少這種浪費的办法不止一種,條件請求是最容易被忽略、又最容易實現的一種。

條件請求是怎么工作的

蜘蛛第一次抓到頁面时,服務器會在响應头里带上 Last-Modified 或 ETag。下次再来,蜘蛛會把這两個值分別放進請求头 If-Modified-Since 和 If-None-Match,相当于問一句:這個版本和上次一样吗?

Last-Modified 與 If-Modified-Since

服務器把請求头里的時間與文件目前的修改時間做比較。如果文件没變,返回 304 Not Modified,並且不带正文;如果變了,返回正常的 200 和完整内容。

ETag 與 If-None-Match

ETag 是内容版本的标识,可以是文件指纹,也可以由内容計算得出。它比時間更精确,适合修改時間不可靠、或者同一秒内多次寫入的场景。两者可以同时存在,服務器一般優先參考 ETag。

304 带来的實际好處

  • 响應体為空,传輸的資料量明顯下降,带宽占用减少。
  • 服務器不必重新渲染整個頁面,响應時間通常比完整請求短。
  • 蜘蛛用更少的時間確認一批 URL 没有變化,省下的抓取額度可以分给新頁面和更新頁面。
  • 源站压力下降,抓取高峰时更不容易出現超时。

需要說明的是,304 只是让重复抓取變便宜,它不會直接让新頁面更快被發現。URL 發現仍然要靠内鏈、Sitemap 這些入口。

几種让 304 失效的常见情形

  • Last-Modified 每次請求都變。有些程序直接拿目前時間当修改時間,蜘蛛带回来的時間永遠對不上,于是每次都拿到 200。
  • ETag 里含進程号或時間戳。同一份内容在不同机器、不同時間生成的 ETag 不一样,條件請求永遠判定為已修改。
  • CDN 或反向代理覆盖了头部。源站設定正确,但邊缘节点重新生成了 ETag,或者强制返回完整响應。
  • 動態頁面没有做内容比對。由資料库查询拼装出来的頁面,如果不額外計算版本标识,就只能一直返回 200。
  • 對首次請求返回 304。没有歷史版本的客戶端拿到 304,頁面内容就完全拿不到了。

在日誌里怎么核對效果

服務器日誌里的狀態碼一栏可以直接看出 304 的比例。做法很简單:把最近的蜘蛛請求按狀態碼分组,看看 200 與 304 各占多少。如果同一批 URL 连續多天全是 200,而頁面内容並没有變化,就說明條件請求没有生效。

顺便留意日誌里 304 的响應字节數是不是接近 0。如果狀態碼是 304 但字节數很大,說明中間层仍在传輸完整正文,节省的效果並没有落到實處。

配置时的几点建议

  1. 让 ETag 基于内容本身生成,不要插入時間或随机值。
  2. Last-Modified 使用文件或資料的真實修改時間,不要用請求時間。
  3. 静態资源交给 Web 服務器處理條件請求,動態頁面在應用层做一次内容摘要比對。
  4. 检查 CDN 配置,確認邊缘节点不會替換源站的 ETag,也不會把 304 轉成 200。
  5. 改動後用日誌复核一段時間,確認 304 比例上升,同时没有出現内容错乱。

條件請求不是抓取優化的全部,但它把重复確認這件事的成本压得很低。在抓取額度有限的情况下,省下来的那部分,可以留给真正需要抓的頁面。