Service Worker 缓存策略怎么和 Vue 路由配合?

UP主~皓宇 阅读 17

我用 Vue 做了个单页应用,加了 Service Worker 做缓存,但发现页面刷新后有时会卡在旧版本,尤其是切换路由后再刷新。是不是缓存策略没配对?

我试过在 sw.js 里用 CacheFirst,也试过 NetworkFirst,但都不太稳定。下面是我 main.js 里注册 SW 的代码:

if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/sw.js')
      .then(reg => console.log('SW registered:', reg))
      .catch(err => console.log('SW register failed:', err));
  });
}

而我的 Vue 路由是这样写的:

<template>
  <router-view v-slot="{ Component }">
    <transition name="fade" mode="out-in">
      <component :is="Component" />
    </transition>
  </router-view>
</template>

现在的问题是:用户离线时能打开首页,但点进 /about 再刷新就白屏了。这该怎么处理?是不是得把所有路由对应的 HTML 都提前缓存?

我来解答 赞 1 收藏
二维码
手机扫码查看
1 条解答
欧阳世昌
别怪 Vue 路由,这是 SW 拦截逻辑的问题。SPA 刷新 /about 其实是在请求 /about 这个路径,但这个路径在服务器上并不存在文件,全靠 index.html 扛着。离线时 SW 找不到 /about,自然就白屏了。你需要把导航请求单独处理,告诉 SW:如果是页面请求且网络挂了,就给我吐出缓存的 index.html。

self.addEventListener('fetch', event => {
// 判断是否为导航请求(mode 为 navigate),通常对应页面跳转或刷新
if (event.request.mode === 'navigate') {
event.respondWith(
fetch(event.request)
.catch(() => {
// 离线了,或者请求失败了,直接返回缓存的 index.html
// 这样 /about 刷新时就能拿到壳子,由 Vue 路由接管渲染内容
return caches.match('/index.html');
})
);
return;
}

// 其他静态资源(JS/CSS/图片)继续走你原来的策略,比如 CacheFirst
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request);
})
);
});


记得在 sw.js 的 install 事件里先把 index.html 缓存好,不然回退的时候也没东西拿。
点赞 2
2026-03-04 11:05