條件請求在抓取流程里做了什么
搜尋蜘蛛並不是每次訪問都從头下载頁面。對于已经抓過、並且记下過校驗信息的 URL,下一次請求會带上 If-Modified-Since(對應 Last-Modified)或 If-None-Match(對應 ETag)。服務器判断内容没變,就返回 304 Not Modified,不带响應体。對站点来说省掉了正文传輸,對抓取方来说這次訪問的代價也更低。
需要说清楚的是,304 不會让某個 URL 變成“已更新”,它只是一次確認。所以它不能替代内容更新,也不该被当成提高抓取频率的手段。它的價值在于:頁面确實没變的时候,別让服務器白白吐一遍完整 HTML。
Last-Modified 與 ETag 的寫法要点
Last-Modified
它應该是该 URL 内容最後一次實质變化的 GMT 時間,格式形如 Wed, 21 Oct 2025 07:28:00 GMT。有几点要留意:時間只能向前,不能每次請求都返回目前時間;时区必须是 GMT;格式要标准,缺項或用了本地時間字符串會让解析失敗,條件請求直接失效。
ETag
ETag 是内容指纹,常见做法是對正文做哈希。强校驗寫成带引号的形式,弱校驗加 W/ 前缀。如果頁面由模板拼装,注意別把随机數、時間戳、會话 ID 混進哈希源,否則每次請求 ETag 都不同,等于没配。
两個头同时存在时,服務器應按規范做優先級判断,蜘蛛也會一並携带。只配一個够用,配齐更稳。
常见的配置坑
- Last-Modified 用了應用啟動時間或目前時間,每次請求都在變,頁面等于天天“刚更新”。
- 缓存策略寫成 no-store 或 no-cache,中間层把條件請求头丢掉,回源拿到的永遠是 200。
- CDN 和源站各算一套 ETag,邊缘返回一個、回源返回另一個,蜘蛛手里的校驗值一直對不上。
- Vary 头設定過宽,同一條 URL 被拆成大量缓存變体,304 命中率随之下降。
- 對登入態、個性化区块不做区分,同一個 URL 對不同請求返回不同内容,校驗值天然不稳定。
這些坑有個共同特征:從抓取日誌看就是 200 一大堆,几乎见不到 304。可以把它当成一個排查信号。
從日誌核對 304 的比例
抓取日誌里记錄了狀態碼。把同一時間段内某個目錄或某個模板下的請求拉出来,統計 200 與 304 的比例。内容長期稳定的栏目頁、詳情頁,如果几乎全是 200,就值得回头检查缓存头和校驗头的配置。反過来,更新频繁的列表頁全是 304 也不正常,說明校驗值没有被正确更新。
核對时最好按模板分组,而不是全站算一個總比例。新闻列表頁和帮助文档頁的合理值顯然不同。
與 Sitemap 里 lastmod 的關系
這两個時間解决的不是同一件事。304 是服務器對單次請求的實时回答,lastmod 是站点主動告诉抓取方這條 URL 什么时候變過。如果 lastmod 天天變而内容實际没動,抓取方来了一看是 304,長期下来這個字段的可信度就會下降。两者應当保持一致:内容真變了,lastmod 更新、ETag 變化、返回 200;内容没變,lastmod 不動、返回 304。
上线前可以走的检查清單
- 用一個固定 URL 连續請求两次,第二次带上 If-None-Match 或 If-Modified-Since,確認返回 304。
- 观察 Last-Modified 在多次請求間是否稳定,只在内容改動後才變化。
- 確認 CDN 没有剥离條件請求头,回源行為與直连源站一致。
- 检查是否誤用了 no-store,導致中間层完全不參與缓存协商。
- 按模板抽样統計日誌中的 304 占比,找出明顯異常的分组。
304 只是一個减负手段。该更新的内容、该修的内鏈、该补的入口,還是要老老實實做,別指望靠一個响應碼換来更好的抓取表現。