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

Я только что попытался внедрить сервисных работников для кэширования некоторых файлов 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 в столбце размера с пометкой "от работников сервиса".

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

4 ответа

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

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

Например, /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

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

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

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

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

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

Точный код в статье 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) и один раз при использовании в качестве ключа кеша.

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

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

Посмотрите на книгу Service Worker Cookbook, она включает в себя рецепт 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;
      });
    });
  });
}

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

Другие вопросы по тегам