浏览器缓存需分层精准控制:cache-control优先级高于expires且仅通过http响应头生效,meta标签无效;静态资源设public,max-age=31536000并配合内容哈希,html设no-cache或max-age=0走协商缓存;etag比last-modified更可靠;preload仅用于首屏关键资源,prefetch用于未来路由;service worker需手动管理缓存版本。

浏览器缓存不是“开了就快”,而是必须分层控制、按资源类型精准设置,否则容易出现用户看不到更新、白屏、样式错乱等现象。
Cache-Control 优先级高于 Expires,且必须服务端配合
前端写 <meta http-equiv="Cache-Control" content="max-age=3600"> 是无效的——Cache-Control 只能通过 HTTP 响应头生效。浏览器忽略 <meta> 中的该字段。
- 静态资源(JS/CSS/图片)建议设为
Cache-Control: public, max-age=31536000(1年),配合文件内容哈希命名(如main.a1b2c3.js),确保更新后 URL 变化,绕过旧缓存 - HTML 文件应设为
Cache-Control: no-cache或max-age=0,强制每次请求都校验(走协商缓存),避免因 HTML 过期导致新 JS/CSS 加载失败 - 若用 Nginx,配置示例:
location ~* \.(js|css|png|jpg|webp)$ { add_header Cache-Control "public, max-age=31536000"; }
协商缓存依赖 ETag 或 Last-Modified,但 ETag 更可靠
Last-Modified 基于文件修改时间,粒度是秒级,且服务器时钟不同步时会出错;ETag 是内容指纹(如 W/"a1b2c3"),只要内容变,ETag 就变,更适合动态生成或构建产物。
- Webpack/Vite 构建时默认生成内容哈希,配合 Nginx 的
etag on;即可启用强 ETag - 手动禁用 ETag(如
etag off;)会导致协商缓存退化为仅靠Last-Modified,在 CI/CD 多机部署时极易命中脏缓存 - 验证是否生效:打开 DevTools → Network → 看响应头是否有
ETag,再刷新,观察请求是否返回304 Not Modified
preload 和 prefetch 不是“多加载点就更好”
preload 是高优先级、当前页面必用资源的声明式预加载(如关键字体、首屏 CSS);prefetch 是低优先级、未来路由可能需要的资源(如下一屏 JS chunk),浏览器只在空闲时下载。
- 滥用
preload会抢占带宽,反而拖慢首屏渲染。只对<link rel="stylesheet">、<link as="font">、首屏关键<script></script>使用 -
prefetch对单页应用(SPA)有用,但对传统多页站意义不大——用户大概率不会跳转到你 prefetch 的页面 - 错误写法:
<link rel="preload" href="vendor.js">(未加as="script")→ 浏览器无法判断资源类型,降级为普通 fetch,失去优先级优势
Service Worker 缓存需主动管理版本,不兼容 AppCache
AppCache 已被所有现代浏览器废弃,manifest 文件不再解析。Service Worker 是唯一标准方案,但它不会自动更新缓存——你得自己写逻辑。
- 每次更新 SW 脚本(如
sw.js)时,浏览器会拉取新脚本并触发install事件,但旧缓存仍保留,必须在activate阶段调用cache.delete()清理 - 不要缓存 HTML 页面本身(除非是 PWA 离线兜底页),否则会和协商缓存冲突;应缓存 API 响应(需配合
CacheStorage.match()和自定义匹配逻辑) - 本地开发时,Chrome 的 “Update on reload” 开关必须打开,否则 SW 不会随代码变更热更新
缓存策略真正难的不是配置,而是让不同生命周期的资源(HTML 每次都要新、JS/CSS 一年不变、API 响应按业务规则缓存)在同一个域名下互不干扰——这要求你清楚每个请求路径背后的真实语义,而不是统一塞个 max-age=86400。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











