搜尋抓取

304 與條件請求:没變的頁面,怎么让蜘蛛少走一趟

頁面内容没變时,蜘蛛仍可能带着 If-Modified-Since 或 If-None-Match 再請求一次。本文讲條件請求在抓取中的實际作用:ETag 與 Last-Modified 怎么生成才稳定,CDN 與缓存层會带来哪些干扰,哪些頁面适合用 304、哪些不必强求,以及如何從抓取日誌判断它是否真的生效。

搜尋抓取

304 與條件請求:没變的頁面,怎么让蜘蛛少走一趟

蜘蛛抓取一個頁面,服務端要解析、查询、拼装 HTML、传輸;如果這份内容一個月没變,這些工作就重复做了。HTTP 协议里有一套机制专门處理這種情况:條件請求。站点把它用對,可以让蜘蛛對没變化的頁面只拿到一個 304 响應,省下的是双方的资源。

條件請求是怎么跑的

当蜘蛛第二次請求同一個 URL 时,會在請求头里带上 If-Modified-Since 或 If-None-Match,取值分別来自上一次响應里的 Last-Modified 和 ETag。服務端比對之後,如果内容没變,就返回 304 Not Modified,不带正文。蜘蛛據此判断“還是老样子”,不必重新解析頁面。

有两点容易被誤解:304 同样算一次抓取請求,省掉的是带宽和解析工作量,不是訪問次數;另外並非所有抓取器都稳定使用條件請求,是否發送這两個头取决于抓取實現與策略,所以不要把它当成調节抓取频次的主要手段。

让 ETag 稳定下来

最常见的失效原因是 ETag 不稳定。有些框架預設用進程 ID 加時間戳、或者随机值来生成 ETag,同一份内容每次請求都得到不同的值,蜘蛛永遠拿不到 304,這套机制等于白做。

  • 把 ETag 基于内容来算:文件哈希、内容長度加更新時間戳的组合都可以,只要同一内容结果一致。
  • 不要把随机數、請求 ID、會话标识放進 ETag。
  • 頁面里插入了實时資料(倒計时、随机推荐位)时,要么固定這部分輸出,要么接受它一直顯示為“已更新”。

Last-Modified 要给真實的修改時間

Last-Modified 應该反映正文最後一次實质修改的時間,而不是本次請求時間或整体部署時間。如果每次發版都刷新全站頁面的時間戳,蜘蛛會以為整站都變了,结果白抓一遍。尽量按内容维度记錄更新時間,而不是按构建批次统一寫入。

缓存层與 CDN 會改變结果

站点前面挂了 CDN 或反向代理时,條件請求的判定可能發生在那一层。常见的情况有:

  • 带不同 query、cookie、User-Agent 的請求被分開缓存,命中率下降;
  • 邊缘节点改寫了 ETag 或 Last-Modified,回源比對因此失效;
  • 缓存過期時間设得太短,蜘蛛拿到的仍然是带正文的完整响應。

排查时可以看抓取日誌里的狀態碼分布:如果 200 占绝大多數、304 几乎没有,說明條件請求很可能没有生效,值得回头查响應头和缓存配置。

哪些頁面不必强求 304

内容高频變化的首頁、列表頁、资讯流,本来就在持續更新,直接用 200 返回新内容更清楚。真正适合做條件請求的,是那些長期稳定又需要被反复確認的頁面,比如商品詳情、文档、帮助中心、歷史文章。對已经确定下线的頁面,則應该用 404 或 410 明确告知,而不是靠 304 拖着。

把條件請求当成“减少無效传輸”的手段,而不是“减少抓取”的手段,判断标准會清晰很多:内容没變就少传,内容變了就如實返回。

落地检查清單

  1. 抽查几個稳定頁面的响應头,確認 ETag 或 Last-Modified 存在,且不是每次請求都變化。
  2. 用同一份請求头连續請求两次,確認第二次返回 304。
  3. 检查 CDN 是否透传或正确生成這两個头。
  4. 观察抓取日誌中 304 的比例,结合栏目更新频率判断是否合理。
  5. 對高频更新的栏目不强求 304,把精力放在稳定内容的頁面上。

這些調整本身不會让蜘蛛来得更多,但能减少它在没變化的頁面上重复消耗的時間,把抓取资源更多地留给真正有更新、需要被重新處理的 URL。