蜘蛛抓取一個頁面,服務端要解析、查询、拼装 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 拖着。
把條件請求当成“减少無效传輸”的手段,而不是“减少抓取”的手段,判断标准會清晰很多:内容没變就少传,内容變了就如實返回。
落地检查清單
- 抽查几個稳定頁面的响應头,確認 ETag 或 Last-Modified 存在,且不是每次請求都變化。
- 用同一份請求头连續請求两次,確認第二次返回 304。
- 检查 CDN 是否透传或正确生成這两個头。
- 观察抓取日誌中 304 的比例,结合栏目更新频率判断是否合理。
- 對高频更新的栏目不强求 304,把精力放在稳定内容的頁面上。
這些調整本身不會让蜘蛛来得更多,但能减少它在没變化的頁面上重复消耗的時間,把抓取资源更多地留给真正有更新、需要被重新處理的 URL。