You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DNS切换后僵尸PWA仍有流量,重新发布如何保障更新可控?

这真是个让人头疼的状况——Service Worker一旦在用户浏览器里扎下根,哪怕你已经把DNS切回旧网站,它还是会按照之前的逻辑接管请求,简直像个甩不掉的“后台幽灵”。先帮你分析下你贴的Workbox代码和问题的关联,再给你梳理重新发布这类PWA时,必须牢牢掌握的更新管控要点:

先看你现有代码的问题

你贴的Workbox路由配置里,第二个路由的正则/[^\.]*/是个大坑:它会匹配几乎所有不带点的URL,包括你的网站根路径、动态页面路径等等。再加上你用了staleWhileRevalidate策略,这个策略的逻辑是“先返回缓存内容,再后台去服务器更新缓存”——也就是说,哪怕你已经切回旧网站,用户访问时Service Worker还是会优先返回之前缓存的PWA版本,后台更新的请求如果打到旧网站,新内容也会被缓存起来,但用户看到的还是旧的缓存内容,强制刷新也没用,因为Service Worker的缓存优先级高于普通浏览器缓存。

另外,这个HTML缓存没有设置任何过期或清理策略,一旦缓存了内容,就会一直留在用户浏览器里,除非手动清理或者Service Worker主动删除。


重新发布PWA时的核心管控要点

1. 精准控制路由匹配范围

绝对避免用/[^\.]*/这种过于宽泛的正则,一定要明确指定需要缓存的HTML路径,比如只匹配你的求职平台的动态页面:

// 只匹配/jobs/和/profile/开头的动态页面
workbox.routing.registerRoute(
  /\/(jobs|profile)\/.*/,
  workbox.strategies.staleWhileRevalidate({
    cacheName: 'html-cache',
    plugins: [
      // 给HTML缓存加过期策略,7天自动失效
      new workbox.expiration.Plugin({
        maxAgeSeconds: 7 * 24 * 60 * 60,
        maxEntries: 50, // 最多缓存50个页面
      }),
    ],
  })
);

这样既不会误缓存旧网站的内容,也能避免缓存无限期留存。

2. 让Service Worker可被更新、可被紧急注销

  • 版本化缓存:在Service Worker开头加一个版本常量,所有缓存名都带上版本前缀,比如:
    const SW_VERSION = 'v20240520';
    // 图片缓存名
    cacheName: `${SW_VERSION}-images`,
    // HTML缓存名
    cacheName: `${SW_VERSION}-html-cache`,
    
    每次发布更新时,只要修改这个版本号,浏览器就会检测到Service Worker文件有变化,自动触发更新流程。
  • 主动触发更新:在你的主应用代码里添加检查更新的逻辑,比如页面加载时主动检查:
    if ('serviceWorker' in navigator) {
      window.addEventListener('load', async () => {
        const registration = await navigator.serviceWorker.register('/sw.js');
        // 主动检查更新
        registration.update();
        // 监听更新完成事件,提示用户刷新
        registration.addEventListener('updatefound', () => {
          const newWorker = registration.installing;
          newWorker.addEventListener('statechange', () => {
            if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
              alert('有新的更新可用,请刷新页面!');
            }
          });
        });
      });
    }
    
  • 紧急注销机制:如果发布后出问题,要能快速让用户的Service Worker自我销毁。可以部署一个临时的Service Worker,内容如下:
    self.addEventListener('install', () => {
      // 跳过等待,立即激活新的Service Worker
      self.skipWaiting();
    });
    
    self.addEventListener('activate', (event) => {
      event.waitUntil(
        // 注销当前Service Worker
        self.registration.unregister()
          .then(() => {
            // 清理所有缓存
            return caches.keys().then(cacheNames => {
              return Promise.all(
                cacheNames.map(cacheName => caches.delete(cacheName))
              );
            });
          })
          .then(() => {
            // 强制所有打开的页面刷新
            return self.clients.matchAll({ type: 'window' }).then(clients => {
              clients.forEach(client => client.navigate(client.url));
            });
          })
      );
    });
    
    用户下次访问时,这个SW会自动激活,注销自己并清理所有缓存,页面也会强制刷新,恢复到正常状态。

3. 选对缓存策略,别乱用staleWhileRevalidate

  • HTML文件:如果你的求职平台内容更新频繁(比如新职位、新简历),优先用networkFirst策略——先请求服务器最新内容,只有网络失败时才用缓存,确保用户看到的是最新内容:
    workbox.strategies.networkFirst({
      cacheName: `${SW_VERSION}-html-cache`,
      plugins: [
        new workbox.expiration.Plugin({
          maxAgeSeconds: 24 * 60 * 60, // 缓存1天,作为降级方案
        }),
      ],
    })
    
    如果内容更新不频繁,再用staleWhileRevalidate,但一定要配合过期策略。
  • 静态资源(图片、CSS、JS):用cacheFirst没问题,但要设置过期和最大条目,避免缓存过多无用资源,你原来的图片缓存配置是合理的,可以保留。

4. 控制Service Worker的作用域

注册Service Worker时,明确指定作用域,只让它接管PWA相关的路径,别影响网站其他部分:

navigator.serviceWorker.register('/sw.js', { scope: '/jobs/' });

这样SW只会处理/jobs/开头的请求,旧网站的其他路径不会被它干扰。如果你的PWA是整个网站,作用域设为/,但一定要确保路由匹配不会覆盖旧内容。

5. 提前测试更新和回滚流程

发布前一定要测试:

  • 修改Service Worker版本号,确认浏览器能检测到更新,新SW能正常激活,旧缓存被清理。
  • 测试紧急回滚流程:部署注销用的SW,确认能自动清理缓存并注销。

针对你当前的遗留问题

如果还有用户被旧SW困扰,你可以在现在指向旧网站的域名上部署上面提到的紧急注销SW。用户下次访问时,这个SW会自动运行,清理旧缓存、注销自己,然后强制页面刷新,用户就能正常访问旧网站了。

内容的提问来源于stack exchange,提问作者Ken

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 22:57:40