搜尋抓取

蜘蛛回来复查时的 304 响應:Last-Modified、ETag 與 Sitemap lastmod 怎么對齐

蜘蛛抓走一個 URL 之後還會定期回来复查。复查时如果站点能正确回應條件請求,用 304 確認内容没變,就能把带宽和抓取時間留给真正更新的頁面。這篇文章讲清楚 Last-Modified、ETag 與 Sitemap lastmod 三者的關系,以及動態站点里最容易踩的几個坑。

搜尋抓取

蜘蛛回来复查时的 304 响應:Last-Modified、ETag 與 Sitemap lastmod 怎么對齐

蜘蛛把一個 URL 抓走之後,事情並没有結束。過一段時間它會回来复查,確認頁面有没有變化。這個复查動作在抓取日誌里占比很高,如果每次回来都要把整份 HTML 重新传一遍,消耗的是双方的带宽,也占用了本该留给新 URL 的抓取時間。條件請求與 304 响應,就是為這件事准备的。

一、蜘蛛复查时,其實是在做條件請求

不少搜尋引擎蜘蛛在重訪已知 URL 时,會带上 If-Modified-Since 或 If-None-Match 請求头。前者的值来自上一次响應里的 Last-Modified,後者来自上一次的 ETag。這相当于在問服務器一句:從我上次拿到的那份文件之後,内容動過吗?

服務器端的回答通常有三種:

  • 内容没變,返回 304 Not Modified,不带正文;
  • 内容變了,返回 200,附带新的正文與新的 Last-Modified / ETag;
  • 服務器不支持條件請求,直接返回 200 全量内容。

對抓取調度来说,304 是最省事的一種结果:蜘蛛確認頁面還是老样子,轉身去看別的 URL。長期来看,一個能稳定返回 304 的站点,在同样的抓取安排下可以覆盖更多頁面。

二、Last-Modified 和 ETag 要经得起對比

Last-Modified 應当反映内容的真實修改時間

這個值来自文件的修改時間,或資料库中该條记錄的更新時間,而不是每次請求的目前時間。頁面内容没變,它就應该保持不變;反過来,只要正文有實质變化,就應该同步更新,否則蜘蛛會一直以為頁面是舊的。

ETag 不要用随机值或時間戳生成

有些動態站点的 ETag 里混進了進程号、随机數或請求時間,導致同一個頁面的 ETag 每次請求都不同。這样一来,蜘蛛每次都判断為内容有變化,條件請求形同虚设,返回的全是 200 全量正文。ETag 更适合由内容本身推導,比如對正文做一次哈希。

三、Sitemap 里的 lastmod 要和响應头说得一样

Sitemap 的 lastmod 是给蜘蛛看的第一手线索,响應头里的 Last-Modified 是第二次確認。两者如果互相矛盾,抓取判断就會變得混乱:Sitemap 寫着今天更新,實际响應里 Last-Modified 還是三個月前,蜘蛛多跑一趟却什么都没拿到。

  • 批量刷新的 lastmod(全站统一改成同一天)會让所有 URL 同时進入复查队列,短時間内的請求量明顯上升;
  • 只改模板、改侧栏而正文没動时,不一定需要更新 lastmod,除非這次改動确實影响頁面主体内容;
  • lastmod 一旦寫成未来時間,部分蜘蛛會直接忽略這個字段。

四、几個容易踩的坑

  • 用 304 掩盖更新。頁面内容已经改了,服務器却因為缓存策略仍舊返回 304,蜘蛛會繼續按舊版本處理。
  • 内容没變却總返回 200 全量。浪費带宽,也让抓取時間花在重复内容上。
  • 反向代理與源站的時間不一致。邊缘节点缓存的 Last-Modified 與源站生成的對不上,條件請求屡屡失敗,容易出現反复全量抓取。
  • 把條件請求当成拒绝抓取的手段。304 的含义是内容未變,不是不欢迎訪問。

五、一份可执行的检查清單

  1. 随机抽几個頁面,用带 If-Modified-Since 的請求测一遍,看是否稳定返回 304。
  2. 對比同一頁面连續两次响應的 ETag,確認它不會無故變化。
  3. 检查 Sitemap 里的 lastmod 與頁面實际更新時間是否一致,剔除全站同一秒的批量值。
  4. 確認内容更新之後,Last-Modified 與 ETag 會同步變化。
  5. 在服務器日誌里按狀態碼統計抓取比例,看 304 占到多少。

這些設定都不复杂,但需要站点在内容管理流程里把“更新時間”当成一個正经字段来维護。做對了,蜘蛛复查的代價變小,能用来發現和抓取新 URL 的余量就多一点。

304 不是省流量的技巧,而是告诉蜘蛛“這里没變化”的准确回答。回答得越准,抓取安排越顺。