常见問题

入口頁返回 304,搜尋蜘蛛還會重新解析頁面里新加的連結吗?

入口頁日誌里出現 304,就以為搜尋蜘蛛跳過了頁面?其實 304 只是让蜘蛛复用缓存副本,真正的問题往往是缓存内容過期或是空壳。本文拆解蜘蛛處理 304 的顺序,梳理 ETag、Last-Modified、CDN 缓存等常见坑,並给出可执行的自查步骤。

常见問题

入口頁返回 304,搜尋蜘蛛還會重新解析頁面里新加的連結吗?

入口頁明明有蜘蛛訪問,日誌里也记着 304,可頁面里新加的目标連結迟迟没有抓取记錄。這时很多人會怀疑是 304 让蜘蛛“跳過”了這一頁。下面把 304 的實际處理逻辑、容易踩坑的几種情况以及自查方法说清楚。

304 到底意味着什么

304 Not Modified 是服務器對條件請求的回應。搜尋蜘蛛再次訪問一個已经抓過的 URL 时,通常會在請求头里带上 If-Modified-Since(配合 Last-Modified)或 If-None-Match(配合 ETag)。服務器判断内容没變,就返回 304,不返回正文。

關键点在于:304 表示“用你上次那份就行”,並不等于這次請求被忽略。蜘蛛仍會把這次訪問計入抓取记錄,並基于缓存的那份 HTML 做連結提取。

蜘蛛遇到 304 之後的處理顺序

  1. 發起條件請求,带上缓存校驗信息。
  2. 收到 304,不下载正文,直接取本地缓存的 HTML。
  3. 用缓存 HTML 解析連結,得到目标 URL 列表。
  4. 把發現但未抓取的 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 通常没有正文。

降低踩坑概率的做法

  1. 让 Last-Modified 随内容真實變化,不要手工寫死。
  2. ETag 使用與内容相關的方式生成,内容變了 ETag 就要變。
  3. 入口頁這類需要被频繁重新解析的頁面,缓存 TTL 不要设得太長。
  4. 連結尽量寫在服務端輸出的 HTML 里,减少對脚本渲染的依赖。
  5. 更新入口頁後主動做一次缓存刷新,並繼續观察後續抓取日誌。

總结一下:304 不會阻止搜尋蜘蛛解析入口頁里的連結,它只是让蜘蛛复用缓存副本。發現不了新 URL 时,先確認缓存副本是不是舊的、是不是空壳,再去看抓取队列和 robots 規則。把缓存校驗和缓存层這几處理顺,大多數“加了連結没被抓”的問题都能定位到具体环节。