【问题标题】:ServiceWorker: No FetchEvent for javascript triggered request?ServiceWorker:没有用于 javascript 触发请求的 FetchEvent?
【发布时间】:2016-03-02 22:21:12
【问题描述】:

我正在使用 Chrome 稳定版 46。

我有一个非常基本的网站。一个按钮。单击该fetch('a') 和一个打开b<a> 标签。 url ab 都不存在,我打算在 service worker 中捕获它们并返回一个 new Response()

如果我点击获取a 的按钮,服务人员不会参与其中,我会收到 404 错误。
但是,如果我点击指向b 的链接,服务工作者会获取并返回响应。

问题:为什么 Service Worker 没有收到 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');
    })
  );
};

【问题讨论】:

  • 为什么你有一个既异步又延迟的脚本?
  • @DanielHerr 腰带和牙套。

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


【解决方案1】:

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

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

我还想指出,您的示例中的fetch 事件处理程序存在一些问题——如果您总是计划返回一个新的Response 对象,则没有理由调用caches.match(request)。更重要的是,您需要对event.request.url 值进行某种检查,并且仅在新的Response 与您的“特殊” URL 之一匹配时才返回,在您的情况下是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'));
  }
});

【讨论】:

  • 这个问题对我来说太神秘了,我完全忘记了声称只适用于进入新页面而不适用于获取请求!感谢您解除我的好奇心!
  • @Jeff 你有理由使用self.addEventListener 而不是self.on 吗?
  • 等价于stackoverflow.com/a/6348597/385997。使用 aEL 意味着我们可以注册多个回调而不是您通过 onXYZ 获得的单个回调。这对于 fetch 来说尤其重要,因为您可能会以这样一种方式构建您的代码,即您有多个回调,每个回调都有机会通过 reapondWith() 处理事件。
猜你喜欢
  • 2020-09-10
  • 1970-01-01
  • 1970-01-01
  • 2018-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-11
  • 1970-01-01
相关资源
最近更新 更多