全站静态资源缓存需精准识别、稳定写入、可控响应:按URL路径、后缀及参数过滤资源;install阶段预载带版本号的缓存;fetch中仅读缓存不回退网络;activate阶段清理旧缓存并立即接管。

实现全站静态资源缓存,关键不是“拦截所有请求”,而是精准识别、稳定写入、可控响应。重点在于明确哪些资源该进缓存、怎么保证离线时一定可用、以及如何避免新旧版本混用导致页面错乱。
只对真正静态的资源启用缓存逻辑
别依赖 request.destination 判断类型——它在 preload、CORS 或某些 CDN 场景下会失真。更可靠的方式是结合 URL 特征:
- 路径以 /static/、/dist/、/assets/ 开头
- 后缀匹配正则:/\.(js|css|png|jpg|gif|svg|woff2?|ttf|eot|ico|webp)$/i
- 排除含敏感参数的 URL,比如包含 auth=、session= 的请求
- 跳过非 GET 请求(如 POST、PUT),防止误存用户数据或表单响应
install 阶段预载关键资源,确保首次离线可用
光靠 fetch 拦截解决不了“第一次访问就离线”的问题。必须在 install 阶段把确定不变的资源提前写进缓存:
- 使用 caches.open('static-v2.3.1') 打开带版本号的新缓存(不用 static 这类裸名)
- 调用 cache.addAll([ '/dist/app.js', '/dist/main.css', '/assets/logo.svg' ]),路径必须与页面实际请求的 URL 完全一致(含查询参数、大小写、尾部斜杠)
- 配合构建工具生成 manifest.json,自动注入真实资源列表,避免手动维护出错
fetch 事件中只读缓存,不 fallback 网络
对已预载的静态资源,要真正实现“离线即用”,fetch 里就不能再发网络请求:
- 命中缓存直接返回:caches.match(request)
- 未命中不调 fetch(request),而是返回 new Response('', { status: 404 }) 或自定义离线提示页
- HTML 页面单独处理,不纳入此逻辑(它需要动态更新,应走缓存+网络并行)
activate 阶段清理旧缓存,防止多版本混用
每次发布新版本,旧缓存若不清理,会导致页面加载错乱资源(例如 v2 的 JS 加载 v1 的 CSS):
- 在 activate 事件中调用 self.clients.claim(),让新 SW 立即接管所有打开页面
- 遍历 caches.keys(),删除所有不含当前版本标识(如 v2.3.1)的缓存名
- 确保 skipWaiting() 在 install 结束前调用,缩短新旧 SW 共存窗口期










