Javascript 服务工作者正在缓存文件,但从未触发提取事件

Javascript 服务工作者正在缓存文件,但从未触发提取事件,javascript,google-chrome,service-worker,progressive-web-apps,Javascript,Google Chrome,Service Worker,Progressive Web Apps,我刚刚尝试在静态站点(在localhost chrome 47.0.2526.73(64位)上运行)上实现服务工作者来缓存一些JSON文件和其他资产。使用cache.addAll()我已将文件添加到缓存中,当我在chrome中打开“资源”选项卡并单击“缓存存储”时,所有文件都会列出 我遇到的问题是,我的服务人员在中被列为“已激活”和“正在运行”chrome://service-worker-internals 但是,我无法确定工作进程是否真的在拦截请求并提供缓存文件。我添加了事件监听器,即使我

我刚刚尝试在静态站点(在localhost chrome 47.0.2526.73(64位)上运行)上实现服务工作者来缓存一些JSON文件和其他资产。使用cache.addAll()我已将文件添加到缓存中,当我在chrome中打开“资源”选项卡并单击“缓存存储”时,所有文件都会列出

我遇到的问题是,我的服务人员在中被列为“已激活”和“正在运行”chrome://service-worker-internals 但是,我无法确定工作进程是否真的在拦截请求并提供缓存文件。我添加了事件监听器,即使我在ServiceWorkers开发工具实例中记录事件,它也不会到达断点:

this.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open('v1').then(function(cache) {
      console.log(cache);
      return cache.addAll([
        '/json/0.json',
        '/json/1.json',
        '/json/3.json',
        '/json/4.json',
        '/json/5.json',
      ]);
    })
  );
});

this.addEventListener('fetch', function(event) {
  console.log(event);
  var response;
  event.respondWith(caches.match(event.request).catch(function() {
    return fetch(event.request);
  }).then(function(r) {
    response = r;
    caches.open('v1').then(function(cache) {
      cache.put(event.request, response);
    });
    return response.clone();
  }).catch(function() {
  }));
});
基本上,我完全按照HTML5 rocks service workers简介中的描述运行,但我非常确定我的资产不是从缓存中提供的。我注意到,在大小列的devtools的network选项卡中,通过指示“fromserviceworkers”,可以对服务人员提供的资产进行注释


似乎我的代码与示例没有什么不同,但出于某种原因,它从来没有遇到过fetch事件。我的代码要点:

HTML5Rocks文章中的确切代码是

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        // Cache hit - return response
        if (response) {
          return response;
        }

        // IMPORTANT: Clone the request. A request is a stream and
        // can only be consumed once. Since we are consuming this
        // once by cache and once by the browser for fetch, we need
        // to clone the response
        var fetchRequest = event.request.clone();

        return fetch(fetchRequest).then(
          function(response) {
            // Check if we received a valid response
            if(!response || response.status !== 200 || response.type !== 'basic') {
              return response;
            }

            // IMPORTANT: Clone the response. A response is a stream
            // and because we want the browser to consume the response
            // as well as the cache consuming the response, we need
            // to clone it so we have 2 stream.
            var responseToCache = response.clone();

            caches.open(CACHE_NAME)
              .then(function(cache) {
                cache.put(event.request, responseToCache);
              });

            return response;
          }
        );
      })
    );
});

我能看到的最大的一点是,您没有从fetch中克隆
请求
,您需要克隆它,因为它被读取两次,一次是在用于访问网络时(在
fetch
中)当被用作缓存的键时,

如果您没有看到service worker中的标记,则您的页面尚未由service worker控制(您可以通过检查客户端页面中的
navigator.serviceWorker.controller
进行检查)。页面的默认行为是在软件激活后下次访问时受到控制,因此您有两个选项:

  • 注册后刷新页面
  • 在安装和激活期间分别使用
    self.skipWaiting()
    self.clients.claim()
    方法强制服务人员尽快控制客户端
看看这个,它包括一个

一旦解决了控件的问题,就需要修复处理程序。我认为您应该首先应用缓存策略。如果不在缓存中,则转到网络并填充缓存。为此:

self.onfetch = function (event) {
  var req = event.request;
  return event.respondWith(function cacheFirst() {
    // Open your cache.
    return self.caches.open('v1').then(function (cache) {
      // Check if the request is in there.
      return cache.match(req).then(function (res) {
        // If not match, there is no rejection but an undefined response.
        if (!res) {
          // Go to network.
          return fetch(req.clone()).then(function (res) {
            // Put in cache and return the network response.
            return cache.put(req, res.clone()).then(function () {
              return res;
            });
          });
        }
        return res;
      });
    });
  });
}

在看了你的要点和问题之后,我认为你的问题在于范围界定

根据我对service worker(至少是静态文件)的判断,service worker只有它所在目录的最大作用域。也就是说,它不能加载从其结构处或其上方(仅在其结构下方)提取的文件/请求/响应

例如,/js/service-worker.js将只能加载/js/{dirName}/中的文件

因此,如果您将服务工作者的位置更改为web项目的根目录,则应触发fetch事件,并从缓存加载资产

所以类似于/service-worker.js的东西应该能够访问/json目录,因为它比service-worker.js文件更深


这在这里的“注册服务人员”部分有进一步的解释

我为此挣扎了很长一段时间,我认为与此相关的文档严重缺乏。根据我的经验,有一个非常重要的区别:

服务工作者只能在其访问的URL范围之内或之上拦截获取事件

例如,我的sw.js文件位于
/static/sw.js
。当访问位于
/
的我的站点根目录并试图截取
/static/js/common.js
中js文件的获取事件时,获取事件没有被截取,即使我的服务人员的范围是
/static/
,js文件在
/static/js/

一旦我将sw.js文件移动到顶级作用域
/sw.js
,获取事件都被截获。这是因为我使用浏览器
/
访问的页面范围与我的sw.js文件
/
的范围相同


请让我知道这是否为人们澄清了问题,或者如果我不正确

我在Django框架中使用sw.js时也遇到了同样的问题。
我找到了解决方案。

你找到解决方案了吗?我认为@Stephen Archers的提示应该标记为正确。是的,你应该将@Stephen Archers的答案标记为正确。Stephen的答案应该标记为正确。我在将web-worker.js存储在子文件夹/assets/js/中时遇到了同样的问题。在存储文件并注册web worker时,它无法获取get请求。在我将它移动到这个域的根目录后,它工作得很好。服务人员能够访问它自己目录中的文件吗?i、 e
app/service worker.js
,它可以读取
app/offline page.html
?@前缀是的,应该可以。如果serviceworker不在根目录中,我也会遇到同样的问题,serviceworker真的可以在子文件夹中找到吗?谢谢。也为我工作!我从未见过这样的实现使用返回self.caches.open('v1')。那么(函数(cache){你能给我这个方法的链接吗?这是比其他更好的解释。谢谢!@garviand:如果我使用“允许服务器工作者”头作为响应,而不是将我的文件移动到根目录,会发生什么?