Javascript 如何删除有问题的服务工作者,或实施“终止开关”?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33986976/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I remove a buggy service worker, or implement a "kill switch"?
提问by PaquitoSoft
I'm playing with the service worker API in my computer so I can grasp how can I benefit from it in my real world apps.
我正在我的计算机中使用 Service Worker API,因此我可以了解如何在现实世界的应用程序中从中受益。
I came across a weird situation where I registered a service worker which intercepts fetchevent so it can check its cache for requested content before sending a request to the origin. The problem is that this code has an error which prevented the function from making the request, so my page is left blank; nothing happens. As the service worker has been registered, the second time I load the page it intercepts the very first request (the one which loads the HTML). Because I have this bug, that fetch event fails, it never requests the HTML and all I see its a blank page.
我遇到了一个奇怪的情况,我注册了一个拦截fetch事件的 service worker,这样它就可以在向源发送请求之前检查其缓存中的请求内容。问题是这段代码有一个错误,阻止了函数发出请求,所以我的页面是空白的;没发生什么事。由于 service worker 已经注册,我第二次加载页面时它会拦截第一个请求(加载 HTML 的请求)。因为我有这个错误,那个 fetch 事件失败了,它从不请求 HTML,我看到它是一个空白页面。
In this situation, the only way I know to remove the bad service worker script is through chrome://serviceworker-internals/
console.
If this error gets to a live website, which is the best way to solve it?
在这种情况下,我知道删除不良服务工作者脚本的唯一方法是通过chrome://serviceworker-internals/
控制台。如果此错误出现在实时网站上,解决它的最佳方法是什么?
Thanks!
谢谢!
回答by Jeff Posnick
I wanted to expand on some of the other answers here, and approach this from the point of view of "what strategies can I use when rolling out a service worker to production to ensure that I can make any needed changes"? Those changes might include fixing any minor bugs that you discover in production, or it might (but hopefully doesn't) include neutralizing the service worker due to an insurmountable bug—a so called "kill switch".
我想扩展这里的其他一些答案,并从“在将 Service Worker 部署到生产环境时可以使用哪些策略来确保我可以进行任何需要的更改”的角度来解决这个问题?这些更改可能包括修复您在生产中发现的任何小错误,或者可能(但希望不会)包括由于无法克服的错误(即所谓的“终止开关”)而使 Service Worker 失效。
For the purposes of this answer, let's assume you call
为了这个答案的目的,我们假设你打电话
navigator.serviceWorker.register('service-worker.js');
on your pages, meaning your service worker JavaScript resource is service-worker.js
. (See below if you're not sure the exact service worker URL that was used—perhaps because you added a hash or versioning info to the service worker script.)
在您的页面上,这意味着您的 Service Worker JavaScript 资源是service-worker.js
. (如果您不确定使用的确切 Service Worker URL,请参见下文——可能是因为您向 Service Worker 脚本添加了哈希或版本信息。)
The question boils down to how you go about resolving the initial issue in your service-worker.js
code. If it's a small bug fix, then you can obviously just make the change and redeploy your service-worker.js
to your hosting environment. If there's no obvious bug fix, and you don't want to leave your users running the buggy service worker code while you take the time to work out a solution, it's a good idea to keep a simple, no-opservice-worker.js
handy, like the following:
问题归结为如何解决service-worker.js
代码中的初始问题。如果这是一个小错误修复,那么您显然可以进行更改并将其重新部署service-worker.js
到您的托管环境。如果没有明显的bug修复和你不想离开你的用户运行马车服务人员的代码,而你花时间来制定出一个解决方案,这是一个好主意,让一个简单的,无操作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);
});
});
});
*/
That should be all your no-op service-worker.js
needs to contain. Because there's no fetch
handler registered, all navigation and resource requests from controlled pages will end up going directly against the network, effectively giving you the same behavior you'd get without if there were no service worker at all.
这应该是您的无操作service-worker.js
需要包含的所有内容。因为没有fetch
注册处理程序,来自受控页面的所有导航和资源请求最终将直接针对网络,有效地为您提供与根本没有 Service Worker 时相同的行为。
Additional steps
附加步骤
It's possible to go further, and forcibly delete everything stored using the Cache Storage API, or to explicitly unregister the service workerentirely. For most common cases, that's probably going to be overkill, and following the above recommendations should be sufficient to get you in a state where your current users get the expected behavior, and you're ready to redeploy updates once you've fixed your bugs. There is some degree of overhead involved with starting up even a no-op service worker, so you can go the route of unregistering the service workerif you have no plans to redeploy meaningful service worker code.
可以更进一步,强行删除使用Cache Storage API存储的所有内容,或者明确地完全取消注册 Service Worker。对于大多数常见情况,这可能会有点矫枉过正,遵循上述建议应该足以让您处于当前用户获得预期行为的状态,并且一旦您修复了错误,您就可以重新部署更新. 即使是启动一个无操作的 Service Worker 也有一定程度的开销,所以如果你没有计划重新部署有意义的 Service Worker 代码,你可以走取消注册 Service Worker的路线。
If you're already in a situation in which you're serving service-worker.js
with HTTP caching directives giving it a lifetime that's longer than your users can wait for, keep in mind that a Shift + Reloadon desktop browsers will force the page to reload outside of service worker control. Not every user will know how to do this, and it's not possible on mobile devices, though. So don't rely on Shift + Reload as a viable rollback plan.
如果您已经在service-worker.js
使用 HTTP 缓存指令为其提供服务的情况下,它的生命周期比您的用户可以等待的时间长,请记住,桌面浏览器上的Shift + Reload将强制页面在外部重新加载服务工作者控制。并非每个用户都知道如何执行此操作,但在移动设备上也不可能。所以不要依赖 Shift + Reload 作为可行的回滚计划。
What if you don't know the service worker URL?
如果您不知道 Service Worker URL 怎么办?
The information above assumes that you know what the service worker URL is—service-worker.js
, sw.js
, or something else that's effectively constant. But what if you included some sort of versioning or hash information in your service worker script, like service-worker.abcd1234.js
?
上面的信息假定你知道什么服务工作者URL是- service-worker.js
,sw.js
或别的东西的有效不变。但是,如果您在 Service Worker 脚本中包含某种版本控制或哈希信息,例如service-worker.abcd1234.js
?
First of all, try to avoid this in the future—it's against best practices. But if you've already deployed a number of versioned service worker URLs already and you need to disable things for allusers, regardless of which URL they might have registered, there is a way out.
首先,在未来尽量避免这种情况——这是违反最佳实践的。但是,如果您已经部署了许多版本化的 Service Worker URL,并且您需要为所有用户禁用某些功能,无论他们可能注册了哪个 URL,都有一个出路。
Every time a browser makes a request for a service worker script, regardless of whether it's an initial registration or an update check, it will set an HTTP request header called Service-Worker:
.
每次浏览器向 Service Worker 脚本发出请求时,无论是初始注册还是更新检查,它都会设置一个名为Service-Worker:
.
Assuming you have full control over your backend HTTP server, you can check incoming requests for the presence of this Service-Worker:
header, and always respond with your no-op service worker script response, regardless of what the request URL is.
假设您完全控制了后端 HTTP 服务器,您可以检查传入请求是否存在此Service-Worker:
标头,并始终以您的无操作服务工作者脚本响应进行响应,无论请求 URL 是什么。
The specifics of configuring your web server to do this will vary from server to server.
配置您的 Web 服务器以执行此操作的具体细节因服务器而异。
The Clear-Site-Data: response header
Clear-Site-Data: 响应头
A final note: some browsers will automatically clear out specific data and potentially unregister service workers when a special HTTP response header is returned as part of any response: Clear-Site-Data:
.
最后一点:当特殊的 HTTP 响应标头作为任何响应的一部分返回时,某些浏览器会自动清除特定数据并可能取消注册服务工作者:Clear-Site-Data:
。
Setting this header can be helpful when trying to recover from a bad service worker deployment, and kill-switch scenarios are included in the feature's specificationas an example use case.
尝试从错误的 Service Worker 部署中恢复时,设置此标头会很有帮助,并且功能规范中包含终止切换场景作为示例用例。
It's important to check the browser support storyfor Clear-Site-Data:
before your rely solelyon it as a kill-switch. As of July 2019, it's not supported in 100% of the browsers that support service workers, so at the moment, it's safest to use Clear-Site-Data:
along with the techniques mentioned above if you're concerned about recovering from a faulty service worker in all browsers.
检查是很重要的浏览器支持的故事为Clear-Site-Data:
之前你依靠纯粹它作为一个杀死开关。截至 2019 年 7 月,支持 Service Worker 的浏览器并未 100% 支持它,因此目前,Clear-Site-Data:
如果您担心在所有浏览器中从有故障的 Service Worker 中恢复,与上述技术一起使用是最安全的。
回答by Francisco Jordano
That's a really nasty situation, that hopefully won't happen to you in production.
这是一个非常糟糕的情况,希望不会发生在你的生产中。
In that case, if you don't want to go through the developer tools of the different browsers, chrome://serviceworker-internals/
for blink based browsers, or about:serviceworkers
(about:debugging#workers
in the future) in Firefox, there are two things that come to my mind:
在这种情况下,如果您不想通过不同浏览器的开发人员工具,chrome://serviceworker-internals/
对于基于闪烁的浏览器,或者about:serviceworkers
(about:debugging#workers
将来)在 Firefox 中,我会想到两件事:
- Use the serviceworker update mechanism. Your user agent will check if there is any change on the worker registered, will fetch it and will go through the
activate
phase again. So potentially you can change the serviceworker script, fix (purge caches, etc) any weird situation and continue working. The only downside is you will need to wait until the browser updates the worker that could be 1 day. - Add some kind of kill switchto your worker. Having a special url where you can point users to visit that can restore the status of your caches, etc.
- 使用 serviceworker 更新机制。您的用户代理将检查注册的工作人员是否有任何更改,将获取它并
activate
再次进入该阶段。因此,您可能可以更改 serviceworker 脚本,修复(清除缓存等)任何奇怪的情况并继续工作。唯一的缺点是您需要等到浏览器更新可能需要 1 天的时间。 - 为您的工作人员添加某种终止开关。有一个特殊的 url,您可以在其中指向用户访问,可以恢复缓存的状态等。
I'm not sure if clearing your browser data will remove the worker, so that could be another option.
我不确定清除浏览器数据是否会删除工作人员,因此这可能是另一种选择。
回答by Prasanna Jathan
You can 'unregister' the service worker using javascript. Here is an example:
您可以使用 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();
}
}
});
}
回答by Salva
For live situations you need to alter the service worker at byte-level (put a comment on the first line, for instance) and it will be updated in the next 24 hours. You can emulate this with the chrome://serviceworker-internals/ in Chrome by clicking on Updatebutton.
对于实时情况,您需要在字节级别更改 Service Worker(例如,在第一行添加注释),它将在接下来的 24 小时内更新。您可以通过单击更新按钮在 Chrome 中使用 chrome://serviceworker-internals/ 模拟这一点。
This should work even for situations when the service worker itself got cached as the step 9 of the update algorithm set a flag to bypass the service worker.
即使在 Service Worker 本身被缓存的情况下,这也应该有效,因为更新算法的第 9 步设置了一个标志来绕过 Service Worker。
回答by Marco Tolk
I haven't tested this, but there is an unregister()and an update()method on the ServiceWorkerRegistration object. you can get this from the navigator.serviceWorker.
我还没有测试过这个,但是ServiceWorkerRegistration 对象上有一个unregister()和一个update()方法。你可以从 navigator.serviceWorker 得到这个。
navigator.serviceWorker.getRegistration('/').then(function(registration) {
registration.update();
});
update should then immediately check if there is a new serviceworker and if so install it. This bypasses the 24 hour waiting period and will download the serviceworker.js every time this javascript is encountered.
然后更新应立即检查是否有新的 serviceworker,如果有,请安装它。这绕过了 24 小时的等待期,每次遇到这个 javascript 时都会下载 serviceworker.js。
回答by Craig Fisher
In case it helps someone else, I was trying to kill off service workers that were running in browsers that had hit a production site that used to register them. I solved it by publishing a service-worker.js that contained just this:
万一它对其他人有帮助,我试图杀死在浏览器中运行的服务工作者,这些浏览器曾访问过用于注册他们的生产站点。我通过发布一个仅包含以下内容的 service-worker.js 解决了这个问题:
self.globalThis.registration.unregister();