即使在加载新版本的应用程序后服务工作者仍可以显示旧版本应用程序的情况?

问题描述 投票:4回答:2

抱歉,我没有这个问题的可重复测试案例,因为我什至从未见过它会自己发生。我只知道发生这种情况是因为我的应用程序中有客户端登录以及用户的投诉。

问题是:

  1. 我部署了新版本的应用程序
  2. 用户访问我的网站,获取新版本,并成功运行它
  3. 用户再次访问我的网站并获得了我的应用的旧版本

我正在使用服务工作者,我希望可以为这种情况不会发生提供某些保证。当新版本包括IndexedDB模式迁移时,这尤其令人不安,因为那时我的应用程序的旧版本甚至无法使用。

更多详细信息:

我正在使用Workbox 4.3.1。我的服务人员基本上是:

importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js");
workbox.precaching.precacheAndRoute([]);
workbox.routing.registerNavigationRoute("/index.html", {
    blacklist: [
        new RegExp("^/static"),
        new RegExp("^/sw.js"),
    ],
});

workbox.precaching.precacheAndRoute([]);workboxBuild.injectManifest填充。我可以手动确认是否填写了正确的文件。通常,服务人员可以正常工作。我可以在浏览器开发工具中看到它。我可以断开与互联网的连接,但仍可以使用我的应用程序。一切似乎都很好。就像我上面说过的,我从未见过此问题发生,并且我没有可复制的测试用例。

但是我的一些用户遇到了上述问题。我尝试使用客户端错误日志记录进行调查。我向我的应用程序添加了一些代码,以将其版本号存储在localStorage中,并在初始加载时将其与当前运行的版本号进行比较。如果它们不同,它将记录版本号以及一些其他信息:

let registrations = [];
if (window.navigator.serviceWorker) {
    registrations = await window.navigator.serviceWorker.getRegistrations();
}
log({
    hasNavigatorServiceWorker:
        window.navigator.serviceWorker !== undefined,
    registrationsLength: registrations.length,
    registrations: registrations.map(r => {
        return {
            scope: r.scope,
            active: r.active
                ? {
                      scriptURL: r.active.scriptURL,
                      state: r.active.state,
                  }
                : null,
            installing: r.installing
                ? {
                      scriptURL: r.installing.scriptURL,
                      state: r.installing.state,
                  }
                : null,
            waiting: r.waiting
                ? {
                      scriptURL: r.waiting.scriptURL,
                      state: r.waiting.state,
                  }
                : null,
        };
    }),
})

查看我的日志,发现只有1%的用户会出现此问题。这些用户丰富了Firefox(占总流量的4%,但针对此问题的日志条目占18%),但它适用于所有浏览器和操作系统。

而且我看到几乎所有记录都具有这些值:

{
    hasNavigatorServiceWorker: true,
    registrationsLength: 1,
    registrations: [{
        "scope": "https://example.com/",
        "active": {
            "scriptURL": "https://example.com/sw.js",
            "state": "activated"
        },
        "installing": null,
        "waiting": null
    }]
}

据我所知,这些都是正确的值。

我还应注意,我的JavaScript文件的URL中包含一个哈希,因此,当用户请求新版本的服务器时,它不能以某种方式返回我的JavaScript的旧版本。

所以,可能会发生什么?如何解释这种观察到的行为?我还能记录什么以进一步调试它?

我只能提出的唯一方案对我来说似乎非常不现实。喜欢...

  1. 用户加载v1,服务工作者由于某些原因失败
  2. 用户加载v2,服务工作者由于某种原因失败
  3. 用户以某种方式从他们的浏览器缓存中获取v1,因为所有先前的服务工作者都失败了,但是现在服务工作者可以正常工作并将其存储为当前版本

但是我没有证据表明服务人员曾经失败过。我的错误日志中没有任何内容。没有用户抱怨离线支持中断。

如果有帮助,发生此情况的实际网站为https://play.basketball-gm.com/,服务人员位于https://play.basketball-gm.com/sw.js,所有代码均为available on GitHub

而且自大约一年前我开始使用服务人员以来,这个问题一直存在。我终于开始写一个Stack Overflow的问题,因为我已经放弃了希望自己能够解决这个问题,甚至创建一个可重现的测试用例。

javascript service-worker workbox
2个回答
1
投票

以某种方式,用户从其缓存中获取旧版本。删除过时的缓存应该可以解决问题。一旦安装了新的服务工作者并且未使用以前的版本,则将激活新的服务工作者,并且您会收到activate事件。由于旧版本已无法使用,因此现在是删除未使用的缓存的好时机。

self.addEventListener('activate', function(event) {
  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.filter(function(cacheName) {
          // Return true if you want to remove this cache,
          // but remember that caches are shared across
          // the whole origin
        }).map(function(cacheName) {
          return caches.delete(cacheName);
        })
      );
    })
  );
});

在激活期间,其他事件,例如fetch,被放入队列中,因此长时间激活可能会阻止页面加载。保持激活尽可能精简,仅将其用于旧版本处于活动状态时无法执行的操作。


0
投票

根据我的想法,这可能更是为有问题的用户提供的“技术支持”答案。

在开发过程中尝试在本地重新加载自己的React应用程序时,我个人遇到了类似的问题。 (客户端代码)我正在使用隧道服务ngrok。

即使我使用较旧版本的代码终止了该服务,我的网站仍将继续运行。 (在实施修复程序后,我发现这很令人沮丧,并且似乎不起作用)

((技术支持)答案:

可能需要执行“硬重载”,有时需要执行“空缓存和硬重载”,这应清除浏览器。(这实际上取决于站点加载的文件的结构)。

您可以在开发人员控制台打开时访问这些选项。

有关硬刷新的更多详细信息,您可以参考此SO帖子:whats-the-difference-between-normal-reload-hard-reload-and-empty-cache-a

© www.soinside.com 2019 - 2024. All rights reserved.