ServiceWorker:没有针对javascript触发请求的FetchEvent?

时间:2015-11-29 03:10:39

标签: javascript asp.net-web-api fetch service-worker fetch-api

我正在使用Chrome stable 46。

我有一个非常基本的网站。只需一个按钮,即可点击fetch('a')和一个<a>标记即可打开b。网址ab都不存在,我打算在服务工作者中捕获它们,只返回new Response()

如果我点击提取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');
    })
  );
};

1 个答案:

答案 0 :(得分:7)

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

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

我还想指出示例中的fetch事件处理程序存在一些问题 - 如果您一直计划返回一个问题,则没有理由致电caches.match(request)新的Response对象。更重要的是,您需要对event.request.url值进行某种检查,只有当它与您的某个&#34;特殊&#34;匹配时,才会返回新的Response。网址,在您的情况下为ab。现在实施的方式,您的fetch处理程序将无条件地返回虚拟Response,即使它是对您的主页(index.html)的后续请求。这大概不是你想要的。

我添加了gist together来修改您的服务工作者代码,以完成我相信您正在尝试的内容。感谢RawGit,您可以尝试live version。对于后代,这里是修改过的服务工作者代码:

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'));
  }
});