搜尋抓取

304、ETag 與 Last-Modified:缓存协商怎样影响蜘蛛的复查判断

搜尋蜘蛛复查 URL 时常带條件請求头,服務器回 304 就跳過正文传輸。這個机制本身没有問题,但 Last-Modified、ETag 與 CDN 缓存如果配错,可能出現頁面已更新却長期返回 304,或者标识每次變化導致重复下载。本文梳理一次复查請求的完整過程、常见配置失誤與自查思路。

搜尋抓取

304、ETag 與 Last-Modified:缓存协商怎样影响蜘蛛的复查判断

蜘蛛的复查請求並不是每次都從零開始。多數搜尋引擎蜘蛛再次訪問同一個 URL 时,會带上條件請求头:If-Modified-Since(基于上次拿到的 Last-Modified)和 If-None-Match(基于上次拿到的 ETag)。服務器判断内容没變,就回一個 304 Not Modified,蜘蛛知道不用重新下载正文。這個過程看起来只是省流量,實际上會影响蜘蛛對你站点更新节奏的判断。

一次复查請求里的三段對话

第一次抓取:蜘蛛請求 URL,服務器返回 200,正文之外還带上 Last-Modified、ETag、Cache-Control 等响應头。第二次抓取:蜘蛛带上條件請求头。第三次判断:服務器返回 304 或 200。返回 304,蜘蛛通常把這次记為“未變化”;返回 200,蜘蛛拿到新的 HTML,再做解析、比對和後續處理。

問题往往出在第二步和第三步之間的不一致上:响應头里的時間或标识说“没變”,但頁面其實已经改了;或者反過来,标识每次都變,蜘蛛每次都拿到完整正文。

容易踩的几種响應头配置

  • Last-Modified 被寫死或提前。有些程序把该字段统一设成發布時間或站点部署時間,頁面後来更新了,時間却没動,蜘蛛容易持續收到 304。
  • ETag 每次請求都不一样。部分服務器按内容哈希之外的規則生成 ETag,或多台後端之間不统一,同一頁面每次都是新标识,條件請求永遠命中不了 304。
  • Cache-Control 设得過長,又经過 CDN。缓存层压着舊 HTML,蜘蛛拿到的是舊版本,頁面上的新連結自然也不會被及时看到。
  • 動態頁面把 304 当預設响應。個別實現不校驗請求头就回 304,蜘蛛會認為内容長期未變,复查节奏也可能被压低。

304 不等于“没来過”

要分清两件事:304 是内容层面的判断,抓取行為本身仍然發生了一次——蜘蛛發起了請求,占用了连接和服務端资源,只是在传輸阶段省下正文。所以 304 比例高,一般說明缓存协商工作正常,而不是说蜘蛛不来了。真正需要警惕的是两種情况:頁面已经更新但長期返回 304;以及本该稳定的頁面频繁返回 200 且内容几乎一致,白白占用抓取額度。

自查建议

  1. 挑 10–20 個近期更新過的頁面,用带條件請求头的工具各請求一次,记錄狀態碼和响應头。
  2. 對比 Last-Modified 與頁面實际最後編輯時間,看是否同步。
  3. 连續請求同一 URL 两次,確認 ETag 是否稳定,條件請求能否稳定返回 304。
  4. 绕開 CDN 直接請求源站一次,確認缓存层没有長期压住新版本。
  5. 在服務器日誌里按狀態碼統計 304、200、5xx 的占比,重点看重要栏目頁的分布。

和 Sitemap、内鏈的關系

Sitemap 里的 lastmod 是另一條獨立线索,蜘蛛會參考它决定是否提前复查某個 URL,但它替代不了响應头。比較稳妥的做法是让三者保持一致:頁面真實更新時間、Last-Modified、Sitemap lastmod 不要互相打架。内鏈同样如此,指向更新頁面的連結如果一直挂在列表頁靠後的位置,即使响應头正确,URL 被重新發現的時間也會被推迟。

缓存协商解决的是“要不要传正文”,抓取路径解决的是“要不要来這一趟”。两者是不同层面的問题,不要用 304 的比例去判断抓取是否健康。

最後提醒一句:不要為了让蜘蛛频繁回来,故意让每個頁面每次都返回 200 和變化的 ETag。這種做法的代價是抓取額度和带宽,收益却很难驗證。把响應头配准,让更新時間和内容真正對應,是更省事的做法。