如何删除有问题的服务人员或实施“终止开关”?


71

我正在使用计算机中的Service Worker API,因此我可以掌握如何在现实世界的应用程序中从中受益。

我遇到了一种奇怪的情况,我注册了一个服务人员,该服务人员拦截提取事件,因此它可以在将请求发送到源之前检查其缓存中是否包含请求的内容。问题是此代码有一个错误,阻止了该函数发出请求,因此我的页面留为空白;没发生什么事。由于服务工作者已注册,因此第二次加载页面时,它将拦截第一个请求(加载HTML的请求)。因为我有这个错误,所以fetch事件失败,它从不请求HTML,而我看到的都是空白页。

在这种情况下,我知道删除不良服务工作程序脚本的唯一方法是通过chrome://serviceworker-internals/控制台。如果此错误出现在实时网站上,哪种解决方法是最好的?

谢谢!

Answers:


98

我想在这里扩展其他一些答案,并从“将服务人员部署到生产中以确保我可以进行任何必要的更改时使用什么策略”的角度来解决这个问题?这些更改可能包括修复您在生产中发现的所有小错误,或者可能(但希望不会)包括由于无法克服的错误(所谓的“杀死开关”)而中和服务工作者。

出于此答案的目的,我们假设您致电

navigator.serviceWorker.register('service-worker.js');

在您的页面上,这意味着您的服务工作者JavaScript资源为service-worker.js。(如果不确定是否使用了确切的服务工作者URL,请参阅下文,可能是因为您向服务工作者脚本中添加了哈希或版本信息。

问题归结为如何解决service-worker.js代码中的初始问题。如果它是一个小错误修复程序,那么您显然可以进行更改并将其重新部署service-worker.js到托管环境。如果没有明显的错误修复,并且您不想在花时间制定解决方案的同时让用户运行错误的服务工作者代码,则最好保持简单,无操作的 service-worker.js便利,例如以下:

// A simple, no-op service worker that takes immediate control.

self.addEventListener('install', () => {
  // Skip over the "waiting" lifecycle state, to ensure that our
  // new service worker is activated immediately, even if there's
  // another tab open controlled by our older service worker code.
  self.skipWaiting();
});

/*
self.addEventListener('activate', () => {
  // Optional: Get a list of all the current open windows/tabs under
  // our service worker's control, and force them to reload.
  // This can "unbreak" any open windows/tabs as soon as the new
  // service worker activates, rather than users having to manually reload.
  self.clients.matchAll({type: 'window'}).then(windowClients => {
    windowClients.forEach(windowClient => {
      windowClient.navigate(windowClient.url);
    });
  });
});
*/

那应该是您所有无操作service-worker.js需要包含的内容。因为没有fetch注册处理程序,所以来自受控页面的所有导航和资源请求最终都将直接针对网络,从而有效地为您提供了相同的行为,甚至根本不需要服务人员。

附加步骤

可以走得更远,并强行删除使用Cache Storage API存储的所有内容,或者显式完全注销服务工作者。在大多数情况下,这可能是过大的,遵循上述建议应该足以使您处于当前用户具有预期行为的状态,并且在修正错误后就可以重新部署更新了。 。即使是无操作的服务工作者,在启动时也会涉及一定程度的开销,因此,如果您没有重新部署有意义的服务工作者代码的计划,则可以采用注销服务工作者的途径。

如果您已经处在service-worker.js使用HTTP缓存指令的情况下,它的生存期比用户可以等待的时间更长,请记住,桌面浏览器上的Shift + Reload会迫使页面重新加载到外部服务人员控制。并非每个用户都知道如何执行此操作,但是在移动设备上并非不可能。因此,不要依赖Shift + Reload作为可行的回滚计划。

如果您不知道服务人员的网址怎么办?

上面的信息假定你知道什么服务工作者URL是- service-worker.jssw.js或别的东西的有效不变。但是,如果您在服务工作者脚本中包含某种版本控制或哈希信息,该service-worker.abcd1234.js怎么办?

首先,尝试避免将来发生这种情况-这与最佳做法相反。但是,如果您已经部署了许多版本化的Service Worker URL,并且需要为所有用户禁用某些功能,无论他们可能注册了哪个URL,都有一种解决方法。

每当浏览器请求服务工作者脚本时,无论是初始注册还是更新检查,它都会设置一个名为的HTTP请求标头Service-Worker:

假设您完全控制后端HTTP服务器,则可以检查传入请求是否存在此Service-Worker:标头,并且无论请求URL是什么,都始终使用no-op service worker脚本响应进行响应。

配置Web服务器以执行此操作的具体情况因服务器而异。

Clear-Site-Data:响应头

最后要注意的是:某些浏览器将自动清除特定数据,并可能在返回特殊HTTP响应标头作为任何响应的一部分时取消注册服务工作者Clear-Site-Data:

尝试从不良的Service Worker部署中恢复时,设置此标头可能会很有帮助,并且功能规范中包含了kill-switch场景作为示例用例。

重要的是,在您完全依赖浏览器支持Clear-Site-Data:之前,请先检查一下浏览器支持的情况。截至2019年7月,100%支持服务工作者的浏览器均不支持此功能,因此,如果您担心要从所有浏览器中从有故障的服务工作者中恢复,则目前最安全的方法是与上述技术一起使用。Clear-Site-Data:



10

您可以使用javascript“注销”服务工作者。这是一个例子:

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.getRegistrations().then(function (registrations) {
    //returns installed service workers
    if (registrations.length) {
      for(let registration of registrations) {
        registration.unregister();
      }
    }
  });
}

1
必须将其放置在.registe 方法之前,以便在注册之前将其全部注销,或者可以在任何地方运行?
diEcho

8

那真是一个令人讨厌的情况,希望您在生产中不会发生。

在这种情况下,如果你不想去通过不同浏览器的开发者工具,chrome://serviceworker-internals/基于浏览器的眨眼,或about:serviceworkersabout:debugging#workers在未来)在Firefox中,有一些,我想起两件事情:

  1. 使用serviceworker更新机制。您的用户代理将检查注册的工作程序是否有任何更改,将其获取并activate再次进行该阶段。因此,潜在地您可以更改serviceworker脚本,修复(清除缓存等)任何奇怪的情况并继续工作。唯一的缺点是您将需要等到浏览器更新工作程序后才可能需要1天。
  2. 给您的工作人员添加某种终止开关。有一个特殊的URL,您可以在其中指向用户访问,可以恢复缓存的状态等。

我不确定清除浏览器数据是否会删除工作程序,所以这可能是另一种选择。


1
感谢您的回答。选项1对于实时网站而言负担不起。我会看看选项2,但我不是很自信,如果你注册在您的网站最高级别的服务人员会工作(“/”)
PaquitoSoft

4

我还没有测试过,但是ServiceWorkerRegistration对象上有一个unregister()update()方法。您可以从navigator.serviceWorker获取此信息。

navigator.serviceWorker.getRegistration('/').then(function(registration) {
  registration.update();
});

然后,更新应立即检查是否有新的serviceworker,如果有,请安装它。这会绕过24小时的等待期,并且每次遇到此javascript时都会下载serviceworker.js。


3

对于现场情况,您需要在字节级别更改服务工作者(例如,在第一行添加注释),它将在接下来的24小时内进行更新。您可以在Chrome浏览器中使用chrome:// serviceworker-internals /来模仿它,方法是点击“更新”按钮。

即使在更新更新的步骤9设置了一个标志来绕过服务工作者时,服务工作者本身被缓存的情况下,这也应该起作用。


0

万一它对其他人有帮助,我试图杀死在浏览器中运行的服务人员,这些浏览器访问了用于注册他们的生产站点。我通过发布仅包含以下内容的service-worker.js解决了该问题:

self.globalThis.registration.unregister();


可能需要24小时或更长时间才能上班?但是,除此之外看起来还不错。stackoverflow.com/questions/38843970/...
汤姆·安德森

0

我们已经将网站从godaddy.com移到了常规的WordPress安装中。客户端(不是我们)将一个serviceworker文件(sw.js)缓存到了他们所有的浏览器中,这完全把事情搞砸了。我们的网站是一个普通的WordPress网站,没有服务人员。

就像病毒一样,它存在于每个页面中,它不是来自我们的服务器,也无法轻松消除它。

我们在服务器的根目录上创建了一个名为sw.js的新空文件,然后将以下内容添加到站点的每个页面上。

<script>
if (navigator && navigator.serviceWorker && navigator.serviceWorker.getRegistration) {

    navigator.serviceWorker.getRegistration('/').then(function(registration) {
        if (registration) {
              registration.update();
              registration.unregister();
        }
});

}
</script>

我们在另一个网站上有这个(相同的客户,他们在godaddy上有网站)-在浏览器中我称之为错误。当更新机制在服务工作者上得到404时,它就使用旧的!所以你需要做一个。
汤姆·安德森
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.