搜索抓取

蜘蛛回来复查时的 304 响应:Last-Modified、ETag 与 Sitemap lastmod 怎么对齐

蜘蛛抓走一个 URL 之后还会定期回来复查。复查时如果站点能正确回应条件请求,用 304 确认内容没变,就能把带宽和抓取时间留给真正更新的页面。这篇文章讲清楚 Last-Modified、ETag 与 Sitemap lastmod 三者的关系,以及动态站点里最容易踩的几个坑。

搜索抓取

蜘蛛回来复查时的 304 响应:Last-Modified、ETag 与 Sitemap lastmod 怎么对齐

蜘蛛把一个 URL 抓走之后,事情并没有结束。过一段时间它会回来复查,确认页面有没有变化。这个复查动作在抓取日志里占比很高,如果每次回来都要把整份 HTML 重新传一遍,消耗的是双方的带宽,也占用了本该留给新 URL 的抓取时间。条件请求与 304 响应,就是为这件事准备的。

一、蜘蛛复查时,其实是在做条件请求

不少搜索引擎蜘蛛在重访已知 URL 时,会带上 If-Modified-Since 或 If-None-Match 请求头。前者的值来自上一次响应里的 Last-Modified,后者来自上一次的 ETag。这相当于在问服务器一句:从我上次拿到的那份文件之后,内容动过吗?

服务器端的回答通常有三种:

  • 内容没变,返回 304 Not Modified,不带正文;
  • 内容变了,返回 200,附带新的正文与新的 Last-Modified / ETag;
  • 服务器不支持条件请求,直接返回 200 全量内容。

对抓取调度来说,304 是最省事的一种结果:蜘蛛确认页面还是老样子,转身去看别的 URL。长期来看,一个能稳定返回 304 的站点,在同样的抓取安排下可以覆盖更多页面。

二、Last-Modified 和 ETag 要经得起对比

Last-Modified 应当反映内容的真实修改时间

这个值来自文件的修改时间,或数据库中该条记录的更新时间,而不是每次请求的当前时间。页面内容没变,它就应该保持不变;反过来,只要正文有实质变化,就应该同步更新,否则蜘蛛会一直以为页面是旧的。

ETag 不要用随机值或时间戳生成

有些动态站点的 ETag 里混进了进程号、随机数或请求时间,导致同一个页面的 ETag 每次请求都不同。这样一来,蜘蛛每次都判断为内容有变化,条件请求形同虚设,返回的全是 200 全量正文。ETag 更适合由内容本身推导,比如对正文做一次哈希。

三、Sitemap 里的 lastmod 要和响应头说得一样

Sitemap 的 lastmod 是给蜘蛛看的第一手线索,响应头里的 Last-Modified 是第二次确认。两者如果互相矛盾,抓取判断就会变得混乱:Sitemap 写着今天更新,实际响应里 Last-Modified 还是三个月前,蜘蛛多跑一趟却什么都没拿到。

  • 批量刷新的 lastmod(全站统一改成同一天)会让所有 URL 同时进入复查队列,短时间内的请求量明显上升;
  • 只改模板、改侧栏而正文没动时,不一定需要更新 lastmod,除非这次改动确实影响页面主体内容;
  • lastmod 一旦写成未来时间,部分蜘蛛会直接忽略这个字段。

四、几个容易踩的坑

  • 用 304 掩盖更新。页面内容已经改了,服务器却因为缓存策略仍旧返回 304,蜘蛛会继续按旧版本处理。
  • 内容没变却总返回 200 全量。浪费带宽,也让抓取时间花在重复内容上。
  • 反向代理与源站的时间不一致。边缘节点缓存的 Last-Modified 与源站生成的对不上,条件请求屡屡失败,容易出现反复全量抓取。
  • 把条件请求当成拒绝抓取的手段。304 的含义是内容未变,不是不欢迎访问。

五、一份可执行的检查清单

  1. 随机抽几个页面,用带 If-Modified-Since 的请求测一遍,看是否稳定返回 304。
  2. 对比同一页面连续两次响应的 ETag,确认它不会无故变化。
  3. 检查 Sitemap 里的 lastmod 与页面实际更新时间是否一致,剔除全站同一秒的批量值。
  4. 确认内容更新之后,Last-Modified 与 ETag 会同步变化。
  5. 在服务器日志里按状态码统计抓取比例,看 304 占到多少。

这些设置都不复杂,但需要站点在内容管理流程里把“更新时间”当成一个正经字段来维护。做对了,蜘蛛复查的代价变小,能用来发现和抓取新 URL 的余量就多一点。

304 不是省流量的技巧,而是告诉蜘蛛“这里没变化”的准确回答。回答得越准,抓取安排越顺。