浏览器缓存机制详解:Cache-Control 与发版失效处理

7 ℃ 0 条
内容摘要浏览器缓存既能提速也容易踩坑。本文讲清强缓存与协商缓存的区别,梳理 Cache-Control 常用指令含义,并给出 Nginx 按文件类型分级配置示例,说明 index.html 为何用 no-cache 以及构建产物加指纹后如何避免发版失效。
浏览器缓存机制详解:Cache-Control 与发版失效处理

浏览器缓存机制详解

浏览器缓存是前端性能优化的第一道关口。配置得当能让二次访问直接读本地,首屏请求数减少一半以上;配置失当则会让用户长期停留在旧版本页面,改完代码看不到效果。本文从缓存头语义讲到构建产物指纹,给出一套可落地的方案。

一、浏览器缓存的两种命中方式

1. 强缓存与协商缓存的区别

浏览器读缓存分两步。强缓存在有效期内不发请求,直接使用本地副本;协商缓存每次都向服务器确认,未变更时返回 304,只传响应头不传响应体。走哪条路由响应头决定:

  • 强缓存:Cache-Control 的 max-age,以及 HTTP/1.0 遗留的 Expires
  • 协商缓存:ETag / If-None-Match、Last-Modified / If-Modified-Since

2. 判断命中了哪一层

在开发者工具 Network 面板看 Size 列:(memory cache) 是同会话内的强缓存命中,(disk cache) 是落盘后的强缓存命中,显示具体字节数说明走了网络。Status 列为 304 则是协商缓存生效。

二、Cache-Control 指令与 Nginx 配置

1. max-age 与 immutable

max-age 单位为秒,带指纹的资源可设一年,再加 immutable 让刷新时也不发条件请求:

Cache-Control: public, max-age=31536000, immutable

刷新页面时浏览器会对强缓存资源强制校验一次,immutable 用于消除这类多余请求。

2. 按文件类型分级配置

不同资源的更新频率差别很大,用一套策略覆盖全站是常见错误:

location ~* \.(js|css|png|webp|woff2)$ {
    expires 1y;
    add_header Cache-Control "public, max-age=31536000, immutable";
}
location = /index.html {
    add_header Cache-Control "no-cache";
}

只给带哈希指纹的资源配长缓存,不带指纹的 app.js 设一年将无法更新。index.html 用 no-cache 而非 no-store,后者每次都会重新下载整个 HTML。

3. stale-while-revalidate 的取舍

该指令允许缓存过期后先返回旧副本、后台异步拉取新版本,对首屏时间友好:

Cache-Control: public, max-age=60, stale-while-revalidate=600

适合更新不敏感的数据接口;登录态、订单金额等强一致场景不要用,否则可能看到上次的价格。

三、构建产物与缓存失效

1. 文件名指纹的作用

强缓存成立的前提是文件名与内容一一对应。构建工具输出的 app.4f2a1b.js 含 contenthash,内容一变文件名就变,因此可放心设一年有效期。index.html 引用这些文件名,自身必须保持不缓存,否则用户拿到的旧 HTML 仍会引用旧 JS。

2. 发版后仍是旧页面的排查顺序

先确认 index.html 是否配了 no-cache;再看 CDN 有无对 HTML 做强制缓存;接着检查 Nginx 的 add_header 是否被子 location 覆盖;最后确认构建产物文件名真的带 contenthash,部分配置会把公共 chunk 固定成 vendors.js。

关键配置提示

  • 带指纹资源用 max-age=31536000, immutable,index.html 用 no-cache
  • Nginx add_header 在子 location 不继承父级设置,需重复声明
  • 改完用 curl -I 核对响应头,浏览器本地缓存需强制刷新后才生效

发表评论 (已有0条评论)

快来评论,快来抢沙发吧~