キャッシュに保存された音声と動画の配信

ブラウザによっては、メディア アセット(<video> 要素と <audio> 要素の src 属性で指定された URL)のリクエストの処理方法にいくつか問題があります。これは Workbox の構成時に特別な手順を実施しないと、誤った配信動作につながる可能性があります。

問題

音声アセットと動画アセットの配信に関してブラウザが抱える問題の複雑さについては、こちらの GitHub の問題ディスカッションで詳しく説明しています。全体像は複雑ですが、要点は次のとおりです。

  • workbox-range-requests モジュールを使用して、ハンドラとして使用する戦略に Range リクエスト ヘッダーを遵守するよう指示する必要があります。
  • <video> 要素または <audio> 要素は、crossorigin 属性で CORS モードにオプトインする必要があります。
  • キャッシュからメディアを提供する場合は、事前に明示的にキャッシュに追加する必要があります。これを行うには、事前にキャッシュするか、cache.add() を使用するか、ワークボックス レシピで暖かい戦略キャッシュのメソッドを使用します。実行時にストリーミングされるメディア アセットをキャッシュに保存しても、再生中にネットワークから一部のコンテンツのみが取得されるため、機能しません。

以下では、ワークボックスでこれらの要件に対応する方法について説明します。まず、メディア アセットの適切なマークアップについて説明します。

<!-- In your page: -->

<!-- You need to set `crossorigin`, even for same-origin URLs! -->
<video src="movie.mp4" crossorigin="anonymous"></video>
<audio src="song.mp3" crossorigin="anonymous"></audio>

次に、Service Worker で workbox-range-request プラグインを使用して、メディア アセットを処理します。

// sw.js
import {registerRoute} from 'workbox-routing';
import {CacheFirst} from 'workbox-strategies';
import {CacheableResponsePlugin} from 'workbox-cacheable-response';
import {RangeRequestsPlugin} from 'workbox-range-requests';

// In your service worker:
// It's up to you to either precache, use warmRuntimeCache, or
// explicitly call cache.add() to populate the cache with media assets.
// If you choose to cache media assets up front, do so with care,
// as they can be quite large and exceed storage quotas.
//
// This route will go to the network if there isn't a cache match,
// but it won't populate the cache at runtime because the response for
// the media asset will be a partial 206 response. If there is a cache
// match, then it will properly serve partial responses.
registerRoute(
  ({request}) => {
    const {destination} = request;

    return destination === 'video' || destination === 'audio'
  },
  new CacheFirst({
    cacheName: 'your-cache-name-here',
    plugins: [
      new CacheableResponsePlugin({
        statuses: [200]
      }),
      new RangeRequestsPlugin(),
    ],
  }),
);

このアプローチでは、ウェブサイトのメディア アセットが Service Worker で適切にフェッチおよびキャッシュされるようにでき、範囲リクエストや、メディア リクエストに関連するその他の潜在的な問題も考慮に入れることができます。