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

old*_*god 3 javascript fetch asp.net-web-api service-worker fetch-api

我正在使用Chrome stable 46.

我有一个非常基本的网站.一个button.onclick fetch('a')和一个<a>打开的标签b.这两个URL 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>
Run Code Online (Sandbox Code Playgroud)

js.js

navigator.serviceWorker.register('sw.js');
Run Code Online (Sandbox Code Playgroud)

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');
    })
  );
};
Run Code Online (Sandbox Code Playgroud)

Jef*_*ick 7

fetch第一次加载页面时不会调用服务工作者的事件处理程序,因为服务工作者尚未"声明"该页面,这意味着它不在服务工作者的控制之下.默认情况下,第一次访问注册服务工作者的站点时,服务工作者install(和可能的activate)事件处理程序将运行,但fetch在服务工作者获得控制权之前不会被触发.下次导航到服务工作者范围下的页面时,或者重新加载当前页面时,会发生这种情况.

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

我还想指出fetch示例中的事件处理程序存在一些问题 - caches.match(request)如果您总是计划返回一个新Response对象,则没有理由调用它.更重要的是,您需要对值进行某种检查,如果它与您的"特殊"URL之一匹配event.request.url,则只返回新的值Response,在您的情况下是ab.现在实现的方式,你的fetch处理程序将Response无条件地返回虚拟,即使它是对你的主页面的后续请求(index.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'));
  }
});
Run Code Online (Sandbox Code Playgroud)

  • 相当于http://stackoverflow.com/a/6348597/385997.使用aEL意味着我们可以注册多个回调,而不是通过onXYZ获得的单个回调.这是特别用于获取的导入,因为您可能以这样的方式构造代码,即您有几个回调,每个回调都有机会通过reapondWith()处理事件. (2认同)