搜尋抓取

304 响應與缓存头:让蜘蛛少重复下载没變的頁面

蜘蛛每次来訪都要重新取一遍 HTML,如果頁面内容没變,這次下载就是白花成本。本文讲 Last-Modified、ETag 两種协商方式怎么配合蜘蛛的請求头,什么情况下服務器该回 304,以及常见的缓存头失效寫法,帮站点把抓取资源留给真正更新的頁面。

搜尋抓取

304 响應與缓存头:让蜘蛛少重复下载没變的頁面

蜘蛛為什么反复下载同一個頁面

蜘蛛来抓一個頁面,無论内容是否變化,預設都要把 HTML 完整取一遍。對站点来说,带宽和响應時間是一部分成本;對蜘蛛来说,它的抓取容量有限,花在没變頁面上的次數越多,能分给新頁面和更新頁面的就越少。缓存协商解决的就是這件事:让服務器有机會告诉蜘蛛「這一份和你上次拿的一样,不用再下了」。

两種协商方式:時間戳與内容指纹

Last-Modified 與 If-Modified-Since

服務器在响應头里给出资源的最後修改時間。蜘蛛下次抓取时,會带上 If-Modified-Since,值就是它上次记下的那個時間。服務器比較後,如果之後没改過,就回 304;改過就返回完整内容和新時間。這一套依赖服務器给出的時間准确。

ETag 與 If-None-Match

ETag 是资源的一個标识串,由服務器按内容或版本生成。蜘蛛下次請求时带 If-None-Match,值就是上次拿到的 ETag。标识一致就回 304。相比時間戳,ETag 的好處是不受时钟和格式精度影响,但前提是這個串要稳定——同一個内容,每次算出来必须一样。

返回 304 时,蜘蛛拿到的是什么

304 不等于「頁面被删」,也不等于「不要抓」。它只表示這次没有新内容可给,蜘蛛會沿用本地已有的副本做後續判断。真正影响是否重新處理的是内容本身有没有變,而不是响應碼是 200 還是 304。所以站点不必担心大量 304 會让頁面掉出索引,需要担心的是反過来——该回 304 的时候回了完整内容,白白增加双方负担。

常见的几種缓存头失效寫法

  • 把 Last-Modified 设成「目前時間」,每次請求都變,协商永遠命中不了。
  • ETag 由随机數、進程号或請求時間拼成,同一份内容每次标识都不同。
  • 反向代理或 CDN 在回源时丢弃、改寫這两個头,源站设了也不生效。
  • 頁面直接輸出 no-store 或 no-cache,等于告诉中間层每次都当新的處理。
  • 静態文件靠查询串刷版本号,内容其實没改,但 URL 變了,缓存也就重新来過。

和 Sitemap 里的 lastmod 不要互相矛盾

两者说的是不同层的事:lastmod 是站点主動声明「這一頁什么时候變過」,缓存头是服務器在單次請求里做的协商。如果 Sitemap 里寫本周更新、响應头里的修改時間却是半年前,蜘蛛會收到两個不一致的信号。更稳妥的做法是让它們来自同一個資料源,頁面内容真正落库的時間,既寫進 Sitemap,也用于生成 Last-Modified。

自查顺序

  1. 用命令行工具带 -I 請求目标頁,看响應头里有没有 Last-Modified 和 ETag。
  2. 手動带上 If-Modified-Since 或 If-None-Match 再請求一次,確認真的返回 304,而不是仍然 200。
  3. 翻站点日誌,統計一段時間内 304 的比例。更新不频繁的栏目頁、文章頁,比例本就不该太低。
  4. 如果用了 CDN,检查回源配置是否保留了這两個头,以及缓存策略有没有覆盖源站設定。

注意邊界

缓存协商是省事的手段,不是省内容的借口。更新频繁的首頁、列表頁,该改就如實改,修改時間要跟着内容走;不要為了少被下载而把時間人為压住。另外,只靠缓存头並不能替代抓取入口和連結结构的建设,它解决的只是「重复下载」這一环。對站点来说,合理的做法是:每個环节各司其职,让蜘蛛把次數花在真正有變化的地方。

一個简單的判断标准:如果一個頁面三個月没動過,蜘蛛每次来還完整下载一遍,那就该看看缓存头了。