web-dev-qa-db-ja.com

Service Workerはファイルをキャッシュしていますが、フェッチイベントは発生しません

サービスワーカーを実装して、いくつかのJSONファイルと他のアセットを静的サイトにキャッシュしようとしました(localhost chromeバージョン47.0.2526.73(64ビット)で実行)。cache.addAll( )ファイルをキャッシュに追加しました。Chromeでリソースタブを開き、キャッシュストレージをクリックすると、すべてのファイルが一覧表示されます。

screenshot json files shown in cache

私が抱えている問題は、サービスワーカーがchrome:// service-worker-internalsで「アクティブ化」および「実行中」としてリストされていることですが、ワーカーが実際にリクエストをインターセプトしてキャッシュファイルを提供しているかどうかを判断できません。イベントリスナーを追加しました。ServiceWorker開発ツールインスタンスでコンソールにイベントを記録しても、ブレークポイントに到達することはありません。

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 Workerのイントロで説明されているとおりに物事を実行していますが、キャッシュからアセットが提供されていないことは確かです。サービスワーカーから提供されるアセットは、「サービスワーカーから」を示すことにより、サイズ列のdevtoolsのネットワークタブにそのように表示されることに注意しました。

私のコードは例と変わらないように見えますが、何らかの理由でフェッチイベントにヒットすることはありません。私のコードの要点: https://Gist.github.com/srhise/c2099b347f68b958884d

42
srhise

あなたの要点とあなたの質問を見た後、私はあなたの問題はスコーピングにあると思います。

サービスワーカーで(少なくとも静的ファイルで)決定したことから、サービスワーカーは、それが入っているディレクトリの最大スコープしか持っていません。つまり、プルされたファイル/リクエスト/レスポンスをロードできません構造上のまたはその上の位置から、下のみ。

たとえば、/ js/service-worker.jsは、/ js/{dirName} /にあるファイルのみをロードできます。

したがって、Service Workerの場所をWebプロジェクトのルートに変更すると、フェッチイベントが発生し、アセットがキャッシュから読み込まれます。

/service-worker.jsのようなものは、/ jsonディレクトリにアクセスできるはずです。service-worker.jsファイルよりも深いからです。

これについては、「サービスワーカーの登録」セクションで詳しく説明します。 https://developers.google.com/web/fundamentals/getting-started/primers/service-workers

62
Stephen Archer

私はこれに長い間苦労しました、そして、私は問題に関連した文書がひどく欠けていると思います。私の経験では、非常に重要な区別があります。

Service Workerは、フェッチイベントがアクセス元のURLのスコープ内またはスコープを超えている場合にのみインターセプトできます。

たとえば、私のsw.jsファイルは/static/sw.jsにありました。 /でサイトのルートにアクセスし、/static/js/common.jsのjsファイルへのフェッチイベントをインターセプトしようとすると、サービスワーカーのスコープが/static/で、フェッチイベントがインターセプトされませんでしたjsファイルは/static/js/にありました。

Sw.jsファイルをトップレベルのスコープ/sw.jsに移動すると、フェッチイベントはすべてインターセプトされました。これは、ブラウザーでアクセスしていたページの範囲/がsw.jsファイル/の範囲と同じだったためです。

これが人々のために物事をきれいにするか、私が間違っているかどうかを教えてください!

28
garviand

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を複製していないことです。それは、ネットワークへのアクセスに使用されるときに2回読み取られるため、複製する必要があります(fetch )およびキャッシュのキーとして使用されるときに1回。

3
Kinlan

from service workerマークが表示されない場合、ページはまだサービスワーカーによってcontrolledではありません(クライアントページでnavigator.serviceWorker.controllerを調べることで確認できます) 。ページのデフォルトの動作は、SWのアクティブ化後に次にアクセスしたときに制御されるようになるため、次の2つのオプションがあります。

  • 登録後にページを更新します。
  • インストールとアクティベーション中にそれぞれself.skipWaiting()メソッドとself.clients.claim()メソッドを使用して、サービスワーカーにクライアントをできるだけ早く制御させます。

Service Worker Cookbook を見てください。これには JSONキャッシュレシピ が含まれています。

コントロールの問題を修正したら、ハンドラーを修正する必要があります。 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;
      });
    });
  });
}
2
Salva

Sw.jsをDjango Frameworkと一緒に使用したときにも同じ問題が発生しました。 Here 解決策を見つけました。

0
petriichuk