Служебный работник кэширует файлы, но событие fetch никогда не запускается

Я только что попытался внедрить рабочих сервисов для кеширования некоторых файлов JSON и других активов на статическом сайте (выполняется на localhost chrome версии 47.0.2526.73 (64-разрядная версия)). Использование cache.addAll() Я добавил файлы в кэш, и когда я открываю вкладку ресурсов в chrome и нажимаю на хранилище кеша, все файлы перечислены.

скриншот json файлов, показанных в кеше

Проблема, с которой я столкнулась, заключается в том, что мой рабочий-сервис указан как "активирован" и "работает" в 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, но я уверен, что мои ресурсы не будут обслуживаться из кеша. Я отметил, что активы, обслуживаемые сервисным работником, отмечены как таковые на вкладке сети devtools в столбце размера, указав "от работников службы".

Кажется, что мой код ничем не отличается от примеров, но по какой-то причине он никогда не ударяет по событию выборки. Суть моего кода: https://gist.github.com/srhise/c2099b347f68b958884d

Ответ 1

Посмотрев на ваш вопрос и ваш вопрос, я думаю, что ваша проблема связана с определением области.

Из того, что я определил с работниками службы (по крайней мере со статическими файлами), рабочий сервис имеет только максимальную область каталога, в котором он находится. То есть он не может загружать файлы/запросы/ответы которые вытаскиваются из места на или над его структурой, только ниже.

Например,/js/service-worker.js сможет загружать файлы только в /js/ {dirName}/.

Поэтому, если вы измените местоположение своего сервисного работника на корень вашего веб-проекта, событие fetch должно быть запущено, а ваши активы должны загружаться из кеша.

Итак, что-то вроде /service -worker.js, которое должно иметь доступ к каталогу /json, поскольку оно глубже, чем файл service-worker.js.

Это поясняется здесь, в разделе "Регистрация работника службы". https://developers.google.com/web/fundamentals/getting-started/primers/service-workers

Ответ 2

Я боролся с этим в течение долгого времени, и я думаю, что документация, связанная с этим вопросом, серьезно отсутствует. По моему опыту, существует очень важное различие:

Сервисный рабочий может только перехватывать события выборки, если он находится в области URL-адреса, к которой он обращается, или находится над ним.

Например, мой файл sw.js находился в /static/sw.js. При доступе к корню моего сайта в / и попытке перехвата событий извлечения в js файлах в /static/js/common.js события выборки не были перехвачены, хотя область моего рабочего-сервиса была /static/, а файл js находился в /static/js/.

Как только я переместил файл sw.js в область верхнего уровня /sw.js, события выборки были перехвачены. Это связано с тем, что область страницы, к которой я обращалась с моим браузером /, была такой же, как область моего файла sw.js /.

Пожалуйста, дайте мне знать, если это очистит людей для людей, или если я ошибаюсь!

Ответ 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 из выборки, вам нужно клонировать его, потому что он читается дважды, один раз при использовании для доступа к сети (в fetch) и один раз при использовании в качестве ключа к кешу.

Ответ 4

Если вы не видите отметку from service worker, то ваша страница не будет контролироваться службой службы еще (вы можете проверить, проверив navigator.serviceWorker.controller на странице клиента). Поведение по умолчанию для страницы должно контролироваться при следующем посещении его после активации SW, поэтому у вас есть два варианта:

  • Обновить страницу после регистрации.
  • Используйте методы self.skipWaiting() и self.clients.claim() во время установки и активации соответственно, чтобы заставить сервисного работника взять под контроль клиентов как можно скорее.

Посмотрите на "Поваренная книга рабочего сотрудника" , она включает в себя рецепт кеша JSON.

Как только вы устраните проблему с помощью элемента управления, вам нужно исправить ваш обработчик. Я думаю, вы хотите применить политику кеша в первую очередь. Если нет в кеше, перейдите в сеть и заполните кеш. Для этого:

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

Ответ 5

У меня была такая же проблема, когда я использовал sw.js с Django Framework. Здесь я нашел решение.