入口頁明明有蜘蛛訪問,日誌里也记着 304,可頁面里新加的目标連結迟迟没有抓取记錄。這时很多人會怀疑是 304 让蜘蛛“跳過”了這一頁。下面把 304 的實际處理逻辑、容易踩坑的几種情况以及自查方法说清楚。
304 到底意味着什么
304 Not Modified 是服務器對條件請求的回應。搜尋蜘蛛再次訪問一個已经抓過的 URL 时,通常會在請求头里带上 If-Modified-Since(配合 Last-Modified)或 If-None-Match(配合 ETag)。服務器判断内容没變,就返回 304,不返回正文。
關键点在于:304 表示“用你上次那份就行”,並不等于這次請求被忽略。蜘蛛仍會把這次訪問計入抓取记錄,並基于缓存的那份 HTML 做連結提取。
蜘蛛遇到 304 之後的處理顺序
- 發起條件請求,带上缓存校驗信息。
- 收到 304,不下载正文,直接取本地缓存的 HTML。
- 用缓存 HTML 解析連結,得到目标 URL 列表。
- 把發現但未抓取的 URL 放進待抓队列,按調度安排抓取。
所以在正常情况下,304 不會導致連結解析失敗。真正让新連結“消失”的,是缓存里那份 HTML 本身就是舊的。
几種容易漏掉新連結的情况
1. 缓存校驗條件没跟着内容變
如果 ETag 是按文件大小或某個固定字符串生成的,Last-Modified 又被寫死成一個很早的時間,那么入口頁即使加了新連結,服務器依然會返回 304。蜘蛛拿到的還是舊 HTML,新連結自然發現不了。
2. CDN 或反向代理缓存了舊頁面
源站已经更新,但 CDN 邊缘节点還在按 TTL 提供舊内容並返回 304。蜘蛛請求打到邊缘节点,结果和上面一样。可以先看响應头里的 Age、X-Cache 之類字段,判断請求命中了哪一层缓存。
3. 頁面靠 JS 渲染,缓存的是空壳
如果入口頁的連結由前端脚本插入,而缓存下来的是首次渲染前的 HTML,304 之後蜘蛛拿到的仍是空壳。這類頁面更依赖服務端直出或预渲染。
304 本身不拦截抓取,它只是让蜘蛛复用已有副本;副本過期或者副本本身就是空壳,才會让新連結一直發現不了。
自查:確認 304 是不是問题源头
- 用 curl -I 查看正常請求返回的 Last-Modified 和 ETag 取值。
- 再带 If-Modified-Since 請求一次,看是否返回 304,同时對比本地缓存版本的 HTML 里有没有新連結。
- 刷新缓存後重新請求,確認返回 200 且正文包含新連結。
- 對照服務器日誌,看蜘蛛拿到的狀態碼和响應体大小,304 通常没有正文。
降低踩坑概率的做法
- 让 Last-Modified 随内容真實變化,不要手工寫死。
- ETag 使用與内容相關的方式生成,内容變了 ETag 就要變。
- 入口頁這類需要被频繁重新解析的頁面,缓存 TTL 不要设得太長。
- 連結尽量寫在服務端輸出的 HTML 里,减少對脚本渲染的依赖。
- 更新入口頁後主動做一次缓存刷新,並繼續观察後續抓取日誌。
總结一下:304 不會阻止搜尋蜘蛛解析入口頁里的連結,它只是让蜘蛛复用缓存副本。發現不了新 URL 时,先確認缓存副本是不是舊的、是不是空壳,再去看抓取队列和 robots 規則。把缓存校驗和缓存层這几處理顺,大多數“加了連結没被抓”的問题都能定位到具体环节。