入口页明明有蜘蛛访问,日志里也记着 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 规则。把缓存校验和缓存层这几处理顺,大多数“加了链接没被抓”的问题都能定位到具体环节。