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

Posted

技术标签:

【中文标题】如何删除有问题的服务人员,或实施“终止开关”?【英文标题】:How can I remove a buggy service worker, or implement a "kill switch"? 【发布时间】:2016-03-03 09:39:45 【问题描述】:

我正在我的计算机中使用 Service Worker API,以便了解如何在我的真实应用中从中受益。

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

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

谢谢!

【问题讨论】:

【参考方案1】:

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

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

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

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

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

// 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 存储的所有内容,或者完全删除到explicitly unregister the service worker。对于最常见的情况,这可能是多余的,遵循上述建议应该足以让您处于当前用户获得预期行为的状态,并且一旦修复了错误,您就可以重新部署更新.即使是启动无操作的 Service Worker 也会产生一定程度的开销,因此如果您没有计划重新部署有意义的 Service Worker 代码,则可以采用 unregistering the service worker 的路线。

如果您已经处于使用 HTTP 缓存指令为 service-worker.js 提供服务的情况下,它的生命周期超过了用户可以等待的时间,请记住,桌面浏览器上的 Shift + Reload 将强制在服务工作者控制之外重新加载的页面。不是每个用户都知道如何做到这一点,但在移动设备上是不可能的。所以不要依赖 Shift + Reload 作为一个可行的回滚计划。

如果您不知道 service worker URL 怎么办?

以上信息假设您知道服务工作者 URL 是什么——service-worker.jssw.js 或其他实际上不变的东西。但是,如果您在 Service Worker 脚本中包含某种版本控制或哈希信息,例如 service-worker.abcd1234.js,会怎样?

首先,以后尽量避免这种情况——它是against best practices。但是,如果您已经部署了许多版本化的 Service Worker URL,并且您需要为 所有 用户禁用某些功能,无论他们可能注册了哪个 URL,都有出路。

每次浏览器对 Service Worker 脚本发出请求时,无论是初始注册还是更新检查,它都会设置一个名为 Service-Worker: 的 HTTP 请求标头。

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

配置您的网络服务器以执行此操作的具体细节因服务器而异。

Clear-Site-Data:响应标头

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

在尝试从错误的 Service Worker 部署中恢复时,设置此标头可能会有所帮助,并且该功能的 specification 中包含了 kill-switch 场景作为示例用例。

在将browser support story 视为Clear-Site-Data: 之前,完全 将其作为终止开关,这一点很重要。截至 2019 年 7 月,支持 Service Worker 的浏览器并非 100% 都支持它,因此目前,如果您担心在所有浏览器。

【讨论】:

另见:github.com/GoogleChrome/workbox/issues/2582【参考方案2】:

我们已将网站从 godaddy.com 移至常规 WordPress 安装。客户(不是我们)有一个服务工作者文件(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 时,它使用旧的!所以你需要做一个。【参考方案3】:

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

self.globalThis.registration.unregister();

【讨论】:

这可能需要 24 小时或更长时间才能工作?但除此之外看起来还可以。 ***.com/questions/38843970/…【参考方案4】:

您可以使用 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();
      
    
  );

【讨论】:

这个必须放在.registe方法之前,这样在注册之前会全部注销还是可以在任何地方运行?【参考方案5】:

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

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

update 应该立即检查是否有新的 serviceworker,如果有,请安装它。这绕过了 24 小时的等待期,每次遇到这个 javascript 时都会下载 serviceworker.js。

【讨论】:

【参考方案6】:

对于实时情况,您需要在字节级别更改服务工作者(例如,在第一行添加注释)和it will be updated in the next 24 hours。您可以通过单击 Update 按钮在 Chrome 中使用 chrome://serviceworker-internals/ 来模拟此操作。

即使在服务工作人员本身被缓存的情况下,这也应该有效,因为更新算法的第 9 步设置了一个标志以绕过服务工作人员。

【讨论】:

【参考方案7】:

这是一个非常糟糕的情况,希望在生产中不会发生在你身上。

在这种情况下,如果您不想通过不同浏览器的开发工具,chrome://serviceworker-internals/ 用于基于 Blink 的浏览器,或about:serviceworkers(将来为about:debugging#workers)在 Firefox 中,有两个我想到的事情:

    使用 serviceworker 更新机制。您的用户代理将检查注册的工作人员是否有任何更改,将获取它并再次通过activate 阶段。因此,您可能可以更改 serviceworker 脚本,修复(清除缓存等)任何奇怪的情况并继续工作。唯一的缺点是您需要等到浏览器更新可能需要 1 天的工作人员。 为您的工作人员添加某种 kill 开关。有一个特殊的 url,您可以指向用户访问,可以恢复缓存的状态等。

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

【讨论】:

感谢您的回答。选项 1 对于实时网站来说是负担不起的。我会看一下选项 2,但如果您在网站顶层 ("/") 上注册 Service Worker,我不太相信它会起作用

以上是关于如何删除有问题的服务人员,或实施“终止开关”?的主要内容,如果未能解决你的问题,请参考以下文章

如何进行数据仓库的建设与实施

如何注销和删除旧的服务人员?

如何拒绝消息

Amazon Appstore DRM - 如何实施?

如何使用 SAML 和 Shibboleth 实施或集成单点登录

电脑装机人员管理软件安装实施人员必备工具包使用教程汇总值得收藏