3

我正在使用 Chrome 稳定版 46。

我有一个非常基本的网站。一个 button.onclickfetch('a')和一个<a>打开的标签b。两个 url都不存在,我打算在服务人员中捕获它们并返回a一个.bnew Response()

如果我单击 fetches 的按钮,a则不涉及服务人员,我会收到 404 错误。
但是,如果我单击指向 的链接,b服务人员会获取并返回响应。

问题:为什么服务人员没有收到fetch('a')请求的任何 FetchEvent?

请参阅下面的文件

HTML

<html>
  <body>
    <p><button onclick="fetch('a');">fetch a</button></p>
    <p><a href="b">go to b</a></p>
    <script src="js.js" defer></script>
  </body>
</html>

js.js

navigator.serviceWorker.register('sw.js');

sw.js

self.onfetch = function(event) {
  var request = event.request;
  event.respondWith(
    caches.match(request).then(function(response) {
      return new Response('here is your onfetch response');
    })
  );
};
4

1 回答 1

7

Service Worker 的fetch事件处理程序在您第一次加载页面时不会被调用,因为 Service Worker 尚未“认领”该页面,这意味着它不受 Service Worker 的控制。默认情况下,当您第一次访问注册了 Service Worker 的站点时,Service Worker 的install(以及可能的activate)事件处理程序将运行,但fetch在 Service Worker 控制之前不会被触发。下次您导航到服务工作者范围内的页面或重新加载当前页面时,就会发生这种情况。

您可以通过在事件处理程序self.clients.claim()内部调用来覆盖此默认行为并让服务工作者在初始导航期间进行控制。activate

我还想指出,您的示例中的事件处理程序存在一些问题——如果您总是计划返回一个新对象,则fetch没有理由调用。更重要的是,您需要对值进行某种检查,并且仅在它与您的“特殊” URL 之一匹配时才返回新值,在您的情况下是and 。现在实现的方式是,您的处理程序将无条件返回虚拟对象,即使它是对您的主页 ( ) 的后续请求。这大概不是你想要的。caches.match(request)Responseevent.request.urlResponseabfetchResponseindex.html

我把一个要点放在一起,修改你的服务工作者代码来完成我相信你正在尝试的事情。借助 RawGit,您可以试用实时版本。对于后代,这是修改后的服务工作者代码:

self.addEventListener('install', event => {
  // Bypass the waiting lifecycle stage,
  // just in case there's an older version of this SW registration.
  event.waitUntil(self.skipWaiting());
});

self.addEventListener('activate', event => {
  // Take control of all pages under this SW's scope immediately,
  // instead of waiting for reload/navigation.
  event.waitUntil(self.clients.claim());
});

self.addEventListener('fetch', event => {
  // In a real app, you'd use a more sophisticated URL check.
  if (event.request.url.match(/a|b$/)) {
    event.respondWith(new Response('here is your onfetch response'));
  }
});
于 2015-12-02T15:17:24.757 回答