很多站点排查抓取問题时只盯着狀態碼是不是 200,忽略了蜘蛛請求头里带的 If-Modified-Since 和 If-None-Match。這两個字段决定了服務器返回 304 還是完整正文,而 304 的占比,直接影响服務器压力和抓取节奏的观察结果。
條件請求是怎么来的
蜘蛛重复抓取一個已知 URL 时,往往會复用上一次拿到的缓存标识。上一次响應带了 Last-Modified,這次請求就會附带 If-Modified-Since;带了 ETag,就會附带 If-None-Match。服務器比對後如果判断内容没變,返回 304 Not Modified,不带响應体。這是标准的 HTTP 协商流程,不是蜘蛛在偷懒。
但要注意,304 依然是一次完整的請求往返。DNS、连接建立、請求头、响應头都要走完,省下的只是响應体传輸和後續解析。所以別把 304 理解成“没有被抓取”,它只是少了正文。
Last-Modified 的常见坑
- 格式不規范:必须使用标准 HTTP 日期格式,輸出時間戳或本地化寫法时蜘蛛可能無法解析,條件請求會退化成每次全量抓取。
- 每次都刷新:動態頁面把 Last-Modified 设成目前時間,等于告诉蜘蛛“每次都變了”,並不能換来更高的抓取频率,反而让修改時間失去參考價值。
- 时区错位:直接輸出服務器本地時間,會让判断出的修改时刻偏早或偏晚,影响對更新节奏的理解。
ETag 的生成方式更關键
ETag 常见两類:一類基于内容摘要,内容不變值就不變;另一類是服務器預設按文件 inode、大小、修改時間拼出来的,多台後端机器之間天然不一致。如果站点走负载均衡或多個 CDN 节点,同一 URL 在不同节点返回不同 ETag,蜘蛛每次带来的條件都匹配不上,于是持續收到 200 和完整正文。
核對时不要只看單台机器。用不同出口 IP 或不同节点請求同一 URL,比較 ETag 是否稳定,比在办公室刷新一次浏览器有用得多。
中間层會改寫什么
反向代理、CDN、WAF 都可能自行增删缓存头。常见情况是源站發了 ETag,邊缘节点统一替換成自己的值;或者源站發了 Last-Modified,压缩處理後把它抹掉。還有一類是中間层把 304 缓存成 200 直接返回完整内容,表面上一切正常,實际每次抓取都在消耗带宽。
實用的核對顺序
- 用 curl 手動带上 If-None-Match 或 If-Modified-Since 請求目标 URL,確認返回的是 304 還是 200。
- 換多個出口 IP 重复同一步骤,观察 ETag、Last-Modified 是否一致。
- 在源站日誌里区分 200 與 304 的數量,找出哪些目錄的 304 占比異常偏低。
- 對確認每次都返回 200 的静態類 URL,检查是不是動態生成的头部让缓存标识失效。
- 如果 Sitemap 里列出的内容頁确實每次都有正文改動,那返回 200 是合理的,不必强行改成 304。
不要為了 304 而 304
304 比例高不等于抓取健康。如果頁面内容确實频繁更新,而服務器因為缓存标识長期不變一直返回 304,蜘蛛就看不到新内容。缓存头的作用是让没變的部分不必反复传輸,而不是把所有請求都變成 304。核對的重点是返回的 304 是否與内容真實變化情况一致。
最後提醒,條件請求只是抓取鏈路中的一环。它能减少無效传輸,但不會因此带来收錄或排名上的直接收益,把它当成服務器资源和抓取节奏的調节手段更合适。