站点运营

站点运营:條件請求與缓存驗證自查,別让蜘蛛每次抓取都全量回源

蜘蛛抓取时,條件請求能让内容未變的頁面返回 304,减少重复传輸。本文說明 Last-Modified、ETag 的常见失效原因,並给出 curl 自查、多节点一致性检查與調整建议,帮助站点运营者把缓存驗證配置得更稳定。

站点运营

站点运营:條件請求與缓存驗證自查,別让蜘蛛每次抓取都全量回源

蜘蛛抓取頁面时,服務器並不需要每次都把完整 HTML 重新發一遍。如果請求里带了驗證信息,而内容没有變化,返回一個 304 狀態碼就能結束這次抓取。這样既省服務器带宽,也减少蜘蛛等待時間。但很多站点在缓存驗證头上配置得比較随意,導致條件請求形同虚设,每次抓取都變成全量回源。

條件請求在做什么

浏览器和蜘蛛在第一次拿到頁面时,服務器通常會在响應头里给出两個驗證器:Last-ModifiedETag。下次再請求同一個地址时,客戶端會把這两個值分別放進 If-Modified-SinceIf-None-Match。服務器比較後如果内容没變,就返回 304 Not Modified,不携带正文。

對蜘蛛来说,304 意味着“這個地址我看過了,内容還是老样子”,它可以很快轉向下一個地址。如果服務器總是返回 200 和完整正文,蜘蛛就得重新下载、重新解析,抓取效率會下降。

容易被忽略的几種失效情况

驗證器每次都在變

有些動態程序會把 Last-Modified 设成目前時間,或者用進程 ID、内存地址生成 ETag。這样每次請求得到的驗證器都不一样,條件請求永遠對不上,304 自然不會出現。

多节点或多层代理不一致

站点有多台源站或经過反向代理、压缩层时,不同节点给出的 ETag 可能不同。蜘蛛這次請求落到 A 节点,下次落到 B 节点,驗證失敗,又會拿到 200 响應。

压缩层改寫了 ETag

開啟 gzip 或 Brotli 後,响應体的字节變了,但 ETag 如果還是按原始内容計算,就可能出現驗證不匹配。部分服務器會改用弱 ETag(W/ 前缀),這本身没問题,但要確認整個鏈路行為一致。

Cache-Control 與驗證头冲突

Cache-Control 里寫了 no-store 或极短的 max-age,同时又依赖 ETag 做驗證,會让中間缓存直接放弃存储,條件請求也失去意义。

304 响應里带了正文

按規范,304 不應包含消息体。如果程序在 304 後面仍然輸出頁面内容,客戶端可能解析異常,浪費一次請求。

自查步骤

  1. curl -I 连續請求同一個 URL 两次,第一次记下 Last-Modified 和 ETag。
  2. 第二次請求时手動带上 If-Modified-Since 或 If-None-Match,观察是否返回 304。
  3. 如果返回 200,對比两次的 ETag 是否變化,以及 Last-Modified 是否等于目前時間。
  4. 在多台源站或多條线路下重复測試,確認驗證器一致。
  5. 在訪問日誌里統計 304 的比例。比例長期接近零,通常說明條件請求没有生效。
  6. 換用蜘蛛 UA 再测一次,排除按 UA 差异化輸出導致驗證器變化。

調整方向

  • ETag 優先使用内容哈希或稳定的版本号,不要用時間戳、進程号、内存地址。
  • Last-Modified 取自内容最後修改時間,而不是請求發生時間。
  • 源站與代理层统一 ETag 生成規則,压缩层不要随意改寫强 ETag。
  • 對長期不變的静態资源,設定較長的 Cache-Control,並保留 ETag 供驗證。
  • 對频繁更新的頁面,可以缩短 max-age,但不要關閉條件請求。
  • 304 响應只返回头,不輸出正文。

和抓取预算的關系

抓取预算有限时,服務器响應速度、狀態碼、内容是否變化都會影响蜘蛛繼續訪問的意愿。304 不能直接提升排名,但能减少重复传輸,让蜘蛛把時間花在真正變化過的地址上。對内容量大、更新频繁的站点,效果更明顯。

抽查时建议固定几個代表性地址:首頁、栏目頁、詳情頁、静態资源,分別记錄狀態碼、驗證器和响應体积,隔一段時間再對比,看是否有节点漂移。

條件請求属于服務器與协议层面的基础配置,改動不大,但需要定期確認。把它纳入站点巡检清單,和日誌、狀態碼、缓存策略一起看,能避免很多“蜘蛛来了却白跑一趟”的情况。