首页 文章

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

提问于
浏览
37

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

screenshot json files shown in cache

我遇到的问题是我的服务工作者在chrome:// service-worker-internals中被列为“激活”和“正在运行”但是,我无法确定工作人员是否实际上正在拦截请求并提供缓存文件 . 我添加了事件监听器,即使我在服务工作者开发工具实例中控制日志事件,它也从未到达断点:

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摇滚服务工作者介绍中描述的方式运行,但我很确定我的资产不是从缓存中提供的 . 我已经注意到,服务工作者提供的资产在size列中的devtools的网络选项卡中通过指示“来自服务工作者”来注明 .

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

4 回答

  • 2

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

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

    例如,/ js / services-worker.js只能加载/ js / /中的文件 .

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

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

    这将在"Register A service worker"部分进一步解释 . https://developers.google.com/web/fundamentals/getting-started/primers/service-workers

  • 3

    我很长时间都在努力解决这个问题,我认为与此事有关的文件严重缺乏 . 根据我的经验,有一个非常重要的区别:

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

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

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

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

  • 17

    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 ,你需要克隆它,因为它被读取两次,一次用于访问网络时(在 fetch 中)和一次用作缓存的关键 .

  • 54

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

    • 注册后刷新页面 .

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

    看看Service Worker Cookbook,它包含一个JSON cache recipe .

    一旦用控件修复问题,就需要修复处理程序 . 我想你想要应用缓存优先策略 . 如果不在缓存中,则转到网络并填充缓存 . 要做到这一点:

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

相关问题