了解 Service Worker 作用域

Understanding Service Worker scope

我正在尝试在测试页中实现 Service Worker。我的最终目标是一个离线运行的应用程序。文件夹结构如下

/myApp
  ...
  /static
    /mod
      /practice
        service-worker.js
        worker-directives.js
        foopage.js
  /templates
    /practice
      foopage.html

我正在注册一个服务工作者,如下所示(在 service-worker.js 内):

navigator.serviceWorker.register('../static/mod/practice/service-worker.js').then(function(reg) {
    console.log('Registration succeeded. Scope is ' + reg.scope);
    ...
}

我在控制台中看到

Registration succeeded. Scope is https://example.com/static/mod/practice/

如果我的页面位于 https://example.com/practice/foopage,我是否需要确保我的 service worker 范围是 https://example.com/practice/foopage

如果我尝试在 register 函数调用中定义范围,例如

navigator.serviceWorker.register('../static/mod/practice/service-worker.js', { scope: '/practice/foopage/' }).then(function(reg) {
    ...
}

我收到错误

Registration failed with SecurityError: Failed to register a ServiceWorker: The path of the provided scope ('/practice/foopage/') is not under the max scope allowed ('/static/mod/practice/'). Adjust the scope, move the Service Worker script, or use the Service-Worker-Allowed HTTP header to allow the scope.

问题是:scope到底指的是什么?它是service worker最终控制的URL集合吗?我需要将 service-workers.js 移到其他地方吗?如果有,在哪里?

Service Workers 基本上是 Web 应用程序和互联网之间的代理,因此它可以根据需要拦截对网络的调用。

此实例中的范围指的是服务人员能够拦截网络调用的路径。可以使用 scope 属性 明确定义它将涵盖的范围。然而:

Service Worker只能拦截来自Service Worker脚本所在的当前目录及其子目录范围内的请求。 Or as MDN states:

The service worker will only catch requests from clients under the service worker's scope.

The max scope for a service worker is the location of the worker.

由于您的 Service Worker 位于 /static/mod/practice/,因此不允许将其范围设置为 /practice/foopage/。对其他主机的请求,例如https://whosebug.com/foo,无论如何都可以拦截

确保你的 service worker 可以拦截它需要的所有调用的最简单方法是将它放在你的网络应用程序的根目录中 (/)。您还可以使用 http header 覆盖默认限制并手动设置范围(请参阅 Ashraf Sabry 的回答)。

将 service worker 文件保留在项目结构强加的任何目录中,并将 scope 选项设置为 / 并将 Service-Worker-Allowed HTTP header 添加到响应中你的 service worker 文件。

我使用的是 IIS,因此我会将以下内容添加到 web.config 文件中:

<location path="static/mod/practice/service-worker.js">
    <system.webServer>
        <httpProtocol>
            <customHeaders>
                <add name="Service-Worker-Allowed" value="/" />
            </customHeaders>
        </httpProtocol>
    </system.webServer>
</location>

并通过以下方式注册工人:

navigator.serviceWorker.register('/static/mod/practice/service-worker.js', { scope: '/' })
        .then(function (registration)
        {
          console.log('Service worker registered successfully');
        }).catch(function (e)
        {
          console.error('Error during service worker registration:', e);
        });

已在 Firefox 和 Chrome 上测试。

参考Service worker specification

中的例子

对于使用 nginx 的人来说,再简单不过了:

# Given that /static is your route to assets
location /static {
        # using / as root scope
        add_header Service-Worker-Allowed /;
....