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

时间:2015-12-08 03:38:46

标签: javascript google-chrome service-worker progressive-web-apps

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

screenshot json files shown in cache

我遇到的问题是我的服务工作者被列为"已激活"和"跑步"在chrome:// service-worker-internals中,我无法确定该worker是否实际上是在拦截请求并提供缓存文件。我添加了事件监听器,即使我在服务工作者开发工具实例中控制日志事件,它也永远不会到达断点:

/tweeting

基本上我正在按照HTML5中描述的方式运行服务工作者介绍,但我很确定我的资产不是从缓存中提供的。我已经注意到,服务工作人员提供的资产在尺寸列中的devtools的网络标签中通过指示来自服务工作者的信息而被注明。

看起来好像我的代码与示例没什么不同,但是由于某种原因它并没有达到fetch事件。我的代码要点:https://gist.github.com/srhise/c2099b347f68b958884d

5 个答案:

答案 0 :(得分:60)

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

根据我对服务工作者的判断(至少使用静态文件),服务工作者只有最大的目录范围。也就是说,它无法加载文件/请求/响应从其结构或其上方的位置拉出,仅在下方。

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

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

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

这里将在"注册A服务工作者"中进一步解释。部分。 https://developers.google.com/web/fundamentals/getting-started/primers/service-workers

答案 1 :(得分:27)

我很长时间以来一直在努力,我认为与此事有关的文件严重缺乏。根据我的经验,有一个非常重要的区别:

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

例如,我的s​​w.js文件位于/static/sw.js。在/访问我的站点根目录并尝试拦截f /static/js/common.js中的js文件的fetch文件时,即使我的服务工作者的范围是/static/,也没有拦截获取事件。 js文件位于/static/js/

将sw.js文件移至顶级作用域/sw.js后,抓取事件全部被截获。这是因为我使用浏览器/访问的页面范围与我的sw.js文件/的范围相同。

如果这样可以为人们解决问题,或者我不正确,请告诉我们。

答案 2 :(得分:3)

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

我能看到的最重要的事情是你没有从抓取中克隆request,你需要克隆它,因为它被读取两次,一次用于访问网络时(在{{ 1}})和一次用作缓存的密钥。

答案 3 :(得分:2)

如果您没有看到标记from service worker,那么服务工作人员的页面不是受控(您可以通过检查客户端页面中的navigator.serviceWorker.controller进行检查) 。页面的默认行为是在SW激活后下次访问时控制,因此您有两个选项:

  • 注册后刷新页面。
  • 分别在安装和激活期间使用self.skipWaiting()self.clients.claim()方法强制服务工作者尽快控制客户端。

查看Service Worker Cookbook,其中包含JSON cache recipe

使用控件修复问题后,您需要修复处理程序。我想您要应用 cache-first 的策略。如果不在缓存中,则转到网络并填充缓存。要做到这一点:

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

答案 4 :(得分:0)

当我将sw.js与Django Framework一起使用时,我遇到了同样的问题。 Here我找到了解决方法。