公司动态

浏览器缓存全解:强缓存 / 协商缓存实战,线上项目缓存策略落地

📅 2026/7/23 13:15:27
浏览器缓存全解:强缓存 / 协商缓存实战,线上项目缓存策略落地
Hi我是前端人类学一次因缓存策略不当导致的生产事故页面白屏持续数小时影响数千用户。根源竟是 index.html 被设置了 10 分钟的强缓存。文章目录一、缓存是什么为什么它这么重要二、强缓存浏览器说了算的本地库存2.1 什么是强缓存2.2 核心控制头部Cache-Control2.3 被替代的 Expires2.4 强缓存的完整流程三、协商缓存服务器拍板的库存核验3.1两种标识方案方案 1Last-Modified If-Modified-Since基于修改时间方案 2ETag If-None-Match基于唯一标识3.2 协商缓存的乐观锁扩展四、缓存存哪里内存 vs 磁盘五、用户行为如何影响缓存策略六、线上实战从一次生产事故说起6.1 事故背景6.2 事故现象6.3 根因分析6.4 解决方案分级缓存策略6.5 发布流程改进七、最佳实践总结7.1 静态资源JS/CSS/图片7.2 入口 HTML7.3 动态接口7.4 项目配置快速参考八、自测清单一、缓存是什么为什么它这么重要第二次打开一个网页比第一次快得多答案就藏在 HTTP 缓存里——它是减少网络请求、节省带宽、提升页面加载速度的核心手段。浏览器缓存的核心逻辑很简单把请求-响应的数据存到本地下次直接用不用再发网络请求。而这一切的实现靠的是强缓存和协商缓存两层机制。二、强缓存浏览器说了算的本地库存2.1 什么是强缓存就像家里囤的零食——只要没过保质期直接拿出来吃不用再去超市买。强缓存就是浏览器判断缓存没过期直接用本地存储的资源主动权完全在浏览器这边。Network 面板中看到200 (from disk cache)或200 (from memory cache)就是强缓存生效的标志——连网络请求都没发。2.2 核心控制头部Cache-Control强缓存的保质期通过响应头Cache-Control控制常用指令指令含义max-age3600缓存 3600 秒后过期最常用public允许中间缓存如 CDN也存private仅浏览器能存中间缓存不能存no-cache不是不缓存是需要先协商缓存再用no-store完全不缓存每次重新请求2.3 被替代的 Expires在 HTTP/1.0 里强缓存靠Expires绝对时间标记过期。但存在一个坑如果客户端和服务器时间不同步过期判断就会出错。现在基本用Cache-Control: max-age相对时间替代它。2.4 强缓存的完整流程浏览器首次请求资源服务器返回资源 Cache-Control: max-age3600浏览器把资源和 Cache-Control 一起存到本地1 小时内再次请求直接用本地缓存不发网络请求1 小时后缓存过期进入协商缓存流程三、协商缓存服务器拍板的库存核验如果强缓存过期了是不是必须重新下载不一定——这时候进入协商缓存浏览器带着缓存的标识问服务器资源过期了现在能用不服务器判断后决定是用缓存还是发新资源。协商缓存的标志是响应码304 Not Modified——“资源没变用本地缓存就行”。3.1两种标识方案方案 1Last-Modified If-Modified-Since基于修改时间首次请求服务器返回Last-Modified: Wed, 03 Jan 2026 10:00:00 GMT缓存过期后请求浏览器带上If-Modified-Since: Wed, 03 Jan 2026 10:00:00 GMT服务器对比时间一样返回 304不一样返回 200 新资源先天缺陷资源内容没变但修改时间变了如服务器重启会被误判为更新了时间精度是秒级1 秒内多次修改无法识别部分服务器拿不到资源的修改时间方案 2ETag If-None-Match基于唯一标识服务器给每个资源生成一个唯一标识如哈希值内容变了 ETag 就变。流程首次请求返回ETag: abc123缓存过期后请求浏览器带If-None-Match: abc123服务器对比一致返回 304不一致返回 200 新资源优先级ETag Last-Modified。如果服务器同时返回两个浏览器优先用 ETag。3.2 协商缓存的乐观锁扩展ETag 不仅能用于缓存验证还可以实现 HTTP 层面的乐观锁。比如更新资源时客户端带If-Match: etag值请求服务器只在 ETag 匹配时才执行更新否则返回 412 Precondition Failed——防止并发更新导致数据丢失。四、缓存存哪里内存 vs 磁盘浏览器的缓存存两个地方Memory Cache内存缓存读取极快但关闭标签页就被清空。适合小体积、高频使用的资源如 JS/CSS。Disk Cache磁盘缓存读取稍慢但持久化。适合大体积资源如图片、视频。冷知识浏览器通常把小文件、频繁使用的文件扔内存大文件、不常用的扔硬盘——但完全由浏览器内核控制开发者干预不了。五、用户行为如何影响缓存策略面试高频题地址栏回车、F5 刷新、CtrlF5 三者的缓存策略有什么区别1. 最懒模式地址栏回车 / 点击链接优先看本地强缓存。没过期就不发请求Network 显示200 (from cache)。只有强缓存失效了才会去问服务器。这是最利用缓存的方式。2. 怀疑模式按 F5 刷新无视强缓存有效期——哪怕 max-age 还有 100 年也会强制发起请求。但还没完全放弃会带上If-Modified-Since或If-None-Match去问服务器改了吗没改返回 304改了返回 200。本质是浏览器在请求头加了Cache-Control: max-age0导致强缓存失效。3. 暴力模式CtrlF5Mac: CmdShiftR完全绕过所有缓存机制。浏览器会① 删除/忽略所有本地缓存② 请求头带Cache-Control: no-cache和Pragma: no-cache。相当于告诉服务器“别给我 304我要 200 和新内容。”用户行为不可控怎么办不能依赖用户的刷新行为——应该用HTML 协商缓存 静态资源 Hash 文件名 强缓存的组合拳。六、线上实战从一次生产事故说起6.1 事故背景某 SPA 应用静态资源构建后带contenthash通过 CDN 分发。网关用 Nginxindex.html与静态资源都设置了缓存但未做差异化。发布采用覆盖式上传 CDN 局部刷新。6.2 事故现象部分用户访问空白页或页面样式错乱控制台报资源 404 或运行时异常。复现具有地域性——不同地区表现不同隐身模式明显好转强制刷新后恢复。6.3 根因分析index.html被设置了较长 TTLCache-Control: public, max-age600页面入口在浏览器和 CDN 都被缓存发布后index.html引用新的带指纹的静态资源但部分用户仍持有旧index.html请求旧的 chunk 路径出现 404CDN 刷新不彻底边缘节点与源站内容不一致开启 gzip 后 ETag 与 If-None-Match 不匹配弱校验未生效Service Worker 未及时激活新版本一句话总结入口缓存了资源更新了版本对不上了。6.4 解决方案分级缓存策略入口文档index.html不缓存location /index.html { add_header Cache-Control no-cache, no-store, must-revalidate; add_header Pragma no-cache; add_header Expires 0; }指纹静态资源长期缓存location /static/ { expires 1y; add_header Cache-Control public, max-age31536000, immutable; }构建开启 contenthashoutput.filenamejs/[name].[contenthash:8].jsoutput.chunkFilenamejs/[name].[contenthash:8].chunk.js6.5 发布流程改进原子发布先上传静态资源后发布入口避免入口引用不可用资源CDN 全链路校验发布后验证多个边缘节点的响应头与内容一致性监控与回滚以资源 404 比例、白屏率、JS 错误率设定阈值与自动回滚开关七、最佳实践总结7.1 静态资源JS/CSS/图片文件名带 contenthashmax-age31536000一年加immutable资源更新时 hash 变化浏览器自动请求新资源7.2 入口 HTML设置Cache-Control: no-cache, no-store每次都验证最新版本确保引用的静态资源带正确 hash避免版本错配7.3 动态接口用Cache-Control: no-cache强制走协商缓存——既利用缓存又保证数据新鲜7.4 项目配置快速参考Webpack / Vite 构建产物// 开启 contenthashoutput.filename[name].[contenthash:8].jsNginx 分级缓存# 入口 — 不缓存 location /index.html { add_header Cache-Control no-cache, no-store, must-revalidate; } # 静态资源 — 长期缓存 location /assets/ { expires 1y; add_header Cache-Control public, max-age31536000, immutable; }八、自测清单发布前逐项确认index.html返回no-cache, no-store静态资源返回public, max-age31536000, immutable正常模式、隐身模式、禁用缓存模式分别访问正常CDN 边缘节点响应头一致Service Worker 正确激活新版本监控指标白屏率、JS 错误率正常浏览器缓存是性能优化的利器也是事故的高发点。入口不缓存、资源长期缓存——遵循这个原则配合原子发布与监控就能在性能和可靠性之间找到最佳平衡。