條件請求在抓取流程中的位置
搜尋蜘蛛訪問一個已抓過的 URL 时,通常會带上 If-Modified-Since 或 If-None-Match 請求头。服務器如果判断内容没有變化,返回 304 Not Modified,蜘蛛就不再下载正文,只更新一下抓取记錄。這個机制的作用很直接:减少传輸量,把有限的抓取预算留给新頁面和确有更新的頁面。
問题在于,304 的命中依赖两個响應头:Last-Modified 和 ETag。只要其中一個被错誤地生成、被中間层改寫,或者條件請求头根本没传到源站,蜘蛛就會一直在“全量下载”和“偶尔命中”之間反复,抓取效率明顯下降。
常见異常類型
ETag 每次都變
有些框架預設用 inode、進程 ID、時間戳拼接 ETag,同一份内容在两次請求里會拿到两個不同的值。蜘蛛下次带着舊 ETag 来對不上,只能重新拉全文。這類問题在動態渲染、多實例部署、负载均衡後的站点上特別常见。
Last-Modified 失真
- 每次請求都刷新為目前時間,等于告诉蜘蛛“内容刚刚變了”。
- 時間字段早于實际修改時間,導致蜘蛛認為頁面長期未更新。
- 時間戳使用未来時間,部分客戶端會直接忽略该头。
- 内容更新後没有同步修改時間,304 繼續命中,蜘蛛看不到新内容。
CDN 與源站的头不一致
邊缘节点開啟压缩、内容改寫或图片處理时,可能重新生成 ETag。结果是源站 ETag 與邊缘 ETag 對不上,蜘蛛從不同线路訪問得到不同校驗值,304 命中率被拉低。回源請求头被剥离的情况也存在,源站實际上一直返回 200,條件請求等于没有生效。
304 與 200 交替出現
部分站点在同一 URL 上时而返回 304、时而返回 200 並附带正文,且两次内容並不一致。這通常和缓存策略、灰度發布、多机房資料不同步有關。對蜘蛛来说,這會增加判断成本,也容易造成重复抓取。
排查顺序
- 先看抓取日誌中 304 的占比。如果長期接近零,說明條件請求基本没有生效。
- 用同一 URL 连續請求两次,记錄两次的 ETag 與 Last-Modified 是否稳定。注意要分別從源站地址和對外域名各测一次。
- 手動带上舊的 If-None-Match、If-Modified-Since 發起請求,观察是返回 304,還是被忽略後直接返回 200。
- 检查 CDN 回源配置:是否改寫响應头、是否剥离條件請求头、是否對 HTML 做了額外處理。
- 检查應用层缓存開關。不少 CMS 或框架對登入態、動態參數頁面預設關閉缓存,這類頁面自然拿不到 304。
- 核對内容更新流程:編輯發布之後,Last-Modified 是否随内容真正發生變化。
配置建议
- ETag 建议基于内容哈希生成,同一内容稳定輸出同一個值。
- Last-Modified 與内容實际變動時間保持一致,不要伪造時間。
- HTML 與静態资源分開配置缓存策略,不要共用一套規則。
- CDN 回源时保留條件請求头,邊缘 ETag 與源站 ETag 不要随意重寫。
- 多机房、多實例站点確認内容版本同步,减少 304 與 200 交替。
304 命中率高不代表内容會被更新收錄,它只說明這一次没有重复传輸。内容是否進入索引,仍取决于頁面本身的质量和抓取後的處理。
條件請求是抓取效率里比較容易被忽略的一环。把它和抓取日誌、CDN 回源配置放在一起核對,通常能發現一部分“蜘蛛反复来、頁面却没變化”的抓取浪費。