搜尋抓取

蜘蛛的第二次抓取:304 與條件請求怎么影响回訪成本

蜘蛛回訪舊頁面时,服務器其實有机會只说一句「没變」。條件請求通過 If-Modified-Since 和 If-None-Match 判断内容是否變化,返回 304 就能省下正文传輸。本文讲清 200 與 304 的實际差別、Last-Modified 與 ETag 常见的失效寫法,以及怎么用 curl 和訪問日誌驗證校驗是否生效。

搜尋抓取

蜘蛛的第二次抓取:304 與條件請求怎么影响回訪成本

蜘蛛第一次抓走一個 URL 之後,並不代表它不會再来。真正的成本大头往往在後面的每一次回訪:頁面没變,蜘蛛還是要發一次請求,服務器還是要给一次响應。如果服務器能在响應里明确告诉蜘蛛「自上次以来没變」,這次回訪的成本可以降到很低。這個机制就是條件請求。

條件請求:把「有没有變」交给服務器判断

蜘蛛回訪时,除了常規的請求头,可能還會带上两個額外的头:

  • If-Modified-Since:值来自上次响應里的 Last-Modified。意思是「如果這個時間之後没改過,就別再传内容了」。
  • If-None-Match:值来自上次响應里的 ETag。意思是「如果這個标识還是上次那個,就別再传内容了」。

服務器比對通過,就返回 304 Not Modified,不带正文;比對不通過,就正常返回 200 和完整頁面。對蜘蛛来说,前者意味着几乎不用下载正文,就能確認内容没有變化。

200 和 304 的差別具体在哪

有一点需要说清楚:304 通常仍然會被算作一次抓取請求。蜘蛛還是连了服務器、還是等了响應,只是省掉了正文传輸。所以它的價值主要在三個方面:

  • 减少带宽和传輸時間,尤其是体积大的 HTML 頁面;
  • 让服務器更快返回,單個连接的占用時間變短;
  • 在抓取节奏受限时,快速完成一次「確認」,把時間留给真正需要下载的頁面。

換句话说,304 不會让蜘蛛多来,但能让它来得更省。

哪些寫法會让條件請求失效

實际站点里,條件請求经常被一些不经意的實現破坏掉,表現就是:蜘蛛每次回訪都拿到完整的 200。

1. Last-Modified 每次都變

有些 CMS 在每次渲染时把 Last-Modified 寫成「目前時間」,或者寫成資料库查询時間。這样一来,蜘蛛带上 If-Modified-Since 去比對,永遠比不過,服務器只能老老實實重传一遍。更合适的做法是取這篇文章或這個资源的真實最後修改時間。

2. ETag 里带了不稳定因素

如果 ETag 由内容哈希生成,一般没問题。但如果它掺進了進程 ID、請求 ID、渲染耗时、随机數,同一個 URL 每次算出来的 ETag 都不一样,If-None-Match 就永遠匹配不上。多台服務器之間 ETag 規則不一致,也會出現同样的结果。

3. 压缩與代理改變了實体

同一個頁面,经過 gzip 和未经過 gzip,實体内容不同,ETag 也可能不同。部分代理會给压缩後的响應加上 W/ 前缀(弱校驗),這是正常的,但要保證同一份内容在不同节点上算出的标识一致。CDN 节点與源站各算一套 ETag,是最容易出問题的地方。

4. Cache-Control 與條件請求互相打架

Cache-Control 里的 no-store、no-cache 這類指令,本意是控制缓存,但如果整套鏈路都不做校驗,回訪就全是完整响應。這不一定算错,只是要清楚代價:頁面越多、回訪越频繁,重复传輸的体量就越大。

怎么自己驗證

  1. 用 curl 拿一次响應头,记下 Last-Modified 和 ETag;
  2. 再發一次請求,带上 If-Modified-Since 或 If-None-Match,看返回碼是不是 304;
  3. 對同一個 URL 隔几分钟重复几次,看 ETag 是否稳定;
  4. 在訪問日誌里統計蜘蛛請求中 304 的比例,比例長期接近零,通常說明校驗没生效。

和 Sitemap 里的 lastmod 怎么配合

Sitemap 的 lastmod 是给蜘蛛的「可能有更新」信号,條件請求是蜘蛛来了之後的「實际有没有變」的確認。两者規則要一致:lastmod 标了更新時間,回訪时 Last-Modified 却给另一個值,蜘蛛會反复来確認却總拿到全量内容,白白消耗抓取。把這两個時間對齐,抓取节奏會更平稳。

條件請求不是提速的魔法,它只是把「没變」這件事说得更清楚一点。省下来的每一次正文传輸,都是留给其他頁面的抓取余量。