SEO 百科

浏览器缓存

本页目录

浏览器缓存

浏览器缓存 是浏览器本地的存储,收到的响应留在访客设备上,同一个网址再次被请求时,新鲜期内直接取用这一份,不再走网络。存多久、什么时候必须回源确认,写在 Cache-Control 里,这一行由站长改。回访的人越多,省下的请求越多。

新鲜期与验证

存下来的响应有新鲜和过期两种状态。max-age 给的是新鲜期,单位是秒,从响应生成那一刻开始计时[2]。到期不等于删除,副本还在设备上,浏览器会带着验证标头问一次源站,内容没变就继续用本地这一份。向源服务器要确认的这一步,业内叫回源。

HTTP/1.1 200 OK
Content-Type: text/css
Cache-Control: public, max-age=31536000, immutable
Last-Modified: Tue, 22 Feb 2022 20:20:20 GMT
ETag: "33a64df5"

一个 CSS 文件的响应长这样。immutable 表示正文不会随时间改变,客户端不该再发 If-None-Match 或 If-Modified-Since 去检查更新,用户手动刷新也不发[1]。没写它的时候,过期之后浏览器还要多发一次验证请求:

GET /style.x234dff.css HTTP/1.1
Host: example.com
If-None-Match: "33a64df5"

服务器比对请求里的值和它手上那份的 ETag,两个值一致就返回 304 Not Modified,响应体为空,浏览器继续用本地副本[3]。

指令的取值

Cache-Control 的写法不区分大小写,官方建议用小写,多个指令之间用逗号分隔[1]。浏览器侧常用的是这几条:

指令 浏览器做什么
max-age=31536000 一年之内不再发请求
no-cache 每次用之前先回源验证,副本仍然保存
no-store 什么都不存,每次完整重新下载
private 只允许本机浏览器存,CDN 与代理不得存
immutable 有效期内连验证请求都不发
stale-while-revalidate=<秒> 先给旧副本,同时在后台取新的

no-cache 常被读成“不要缓存”,它要求的是使用前必须验证,副本照旧留在设备上;真正一份不留的写法是 no-store[1]。s-maxage 只作用于共享缓存,私有缓存会忽略它[1],浏览器这一侧看的还是 max-age。表里最后一条不在核心规范里,属于扩展指令,用之前要查一遍兼容性[1]。

三类资源的配法

  • 带哈希的静态文件:Cache-Control: public, max-age=31536000, immutable。文件名里的哈希串随内容改变,旧副本自然作废。
  • 频繁改动的 HTML:Cache-Control: no-cache,再配上 ETag 与 Last-Modified,内容没改时只花一次 304 的往返[2]。
  • 含个人信息的响应:Cache-Control: private,涉及密码或支付页时改用 no-store[1]。

回访者的收益落在哪

可交互时间(TTI)是一种实验室指标,衡量从网页开始加载,到主要子资源加载完成、能够快速可靠地响应用户输入的时间[4]。Google 给出的通用优化方向里,有一项是保持较低的请求数量和较小的传输大小[4]。首次访问要下的 CSS 与 JavaScript,在回访时直接命中本地缓存,请求数下降,主线程更早空出来,TTI 随之前移。最大内容绘制(LCP)也吃这一层,样式与首屏图片不必重新下载,绘制完成得更早。

配错的后果

新鲜期设长了,改版后的新内容要等到旧副本过期才开始服务,这期间用户看到的还是旧页。想缩短这段等待有两条路:把新鲜期改短,或者改文件名,前者省不掉请求,后者要动构建流程。

  • 动态页面套用静态资源的长新鲜期,用户看到的是上一次会话的数据。
  • 带个人信息的响应漏写 private,副本留在共享缓存里,发给别的访客。
  • 只改内容不改文件名,新鲜期又设成一年,改动在一年之内到不了用户端。
  • 只在自己机器上验证,忘了节点上也存着一份,别人抓到的仍是旧副本。

附录

参见

参考资料

官方(境外)

  1. 《Cache-Control》,MDN Web 文档。
  2. 《HTTP 缓存》,MDN Web 文档。
  3. 《If-None-Match》,MDN Web 文档。
  4. 《可交互时间 (TTI)》,web.dev。

外部链接

无。