搜尋抓取

條件請求與蜘蛛抓取:Last-Modified、ETag 和 304 到底省了什么

蜘蛛重复抓取同一頁面时,服務器可以通過 Last-Modified 與 ETag 告诉它内容有没有變化。做對了能减少传輸與解析開销,做错了反而让蜘蛛反复下载同一份内容。本文說明條件請求的工作方式、常见配置坑,以及可落地的自查步骤。

搜尋抓取

條件請求與蜘蛛抓取:Last-Modified、ETag 和 304 到底省了什么

蜘蛛第一次抓走頁面之後,還會再来。它再来的时候,服務器其實有机會说一句:這個頁面没變,別下载了。這套机制就是條件請求(Conditional Request)。用對了能减少传輸和解析開销,用错了會让蜘蛛反复拉取同一份内容,甚至拿到過期的判断。

蜘蛛再来时的两次握手

蜘蛛第二次訪問某個 URL 时,如果之前拿到過缓存信息,請求头里可能带上其中之一:

  • If-Modified-Since:值是上次响應里的 Last-Modified 時間。
  • If-None-Match:值是上次响應里的 ETag 标识。

服務器比對之後给出两種结果:内容没變,返回 304 Not Modified,不带响應体;内容變了,返回 200 和完整頁面。對蜘蛛来说,304 意味着它不用重新下载和解析正文,可以直接沿用已有内容。

Last-Modified 常见的失真来源

Last-Modified 看起来最简單,也最容易寫错。動態站点里常见的几種情况:

  • 每次請求都輸出目前時間,等于告诉蜘蛛“刚刚改過”,蜘蛛只能每次完整下载。
  • 内容存在資料库里,文件本身没動,Last-Modified 停留在很早以前,蜘蛛會誤判頁面長期不變。
  • CDN 回源時間被当成资源修改時間,源站更新後缓存层没刷新,時間對不上。

如果站点用的是静態文件加 Nginx,預設的 Last-Modified 来自文件修改時間,通常比較可靠;一旦生成逻辑是動態拼接,就需要手動维護一個真實的“内容更新時間”。

ETag 在多节点环境里更容易出错

ETag 的理论效果比 Last-Modified 更精确,問题出在一致性上:

  • 多台後端各自生成 ETag,值里含 inode、進程号或本地時間戳,同一 URL 在不同机器上返回不同 ETag,蜘蛛會認為内容一直在變。
  • 反向代理、负载均衡或某些中間层會改寫甚至丢弃 ETag,請求里的 If-None-Match 传不到後端。
  • 頁面每次响應都带随机推荐位、時間戳或一次性 token,正文没變但字节變了,ETag 自然每次都不同。
  • 部分服務器對压缩前後的内容分別計算 ETag,gzip 與 br 之間切換时會来回變化。

304 能不能省下抓取预算

需要说清楚一点:從蜘蛛的视角看,304 依然算一次對 URL 的抓取。它节省的是带宽、服務器 CPU 和解析時間,並不直接換来更多抓取次數。所以不要指望靠 304 提升抓取频率,但把它做對,确實能减轻服務器压力,也让蜘蛛更快走完一轮 URL。真正决定蜘蛛来不来的,還是 URL 是否可發現、服務器是否稳定、頁面是否有更新價值。

可落地的自查顺序

  1. 正常抓一次目标頁面,记錄响應头里的 Last-Modified 與 ETag。
  2. 間隔几分钟再抓,手動带上 If-None-Match 或 If-Modified-Since,观察是否返回 304。
  3. 換一台服務器或換一個 CDN 节点重复同样的請求,比較 ETag 是否一致,這一步最容易暴露集群問题。
  4. 修改頁面内容後立刻請求,確認返回的是 200 且带新正文,而不是 304。
  5. 检查中間层是否吞掉了條件請求头,可以對比源站直连與经過 CDN 後的响應差异。
條件請求是一項减少浪費的優化,不是抓取策略的核心。先保證 URL 能被發現、服務器能稳定响應,再考虑用 304 把重复传輸压下来,顺序反了收益很有限。

如果你的站点頁面更新频率很低,做對條件請求的收益會比較明顯;如果内容频繁變動,重点則應该放在让 Last-Modified 反映真實更新,而不是為了凑 304 而保留過时的時間戳。