Diffuser des contenus audio et vidéo mis en cache

La façon dont certains navigateurs traitent les requêtes d'éléments multimédias (l'URL spécifiée dans l'attribut src des éléments <video> et <audio>) peut rendre la diffusion incorrecte, sauf si vous prenez des mesures spécifiques lors de la configuration de Workbox.

Problème

Les subtilités des problèmes que rencontrent les navigateurs pour diffuser des assets audio et vidéo sont expliqués en détail dans cette discussion sur GitHub. La situation dans son ensemble est complexe, mais les points clés sont les suivants:

  • Il faut indiquer à Workbox de respecter les en-têtes de requête Range en utilisant le module workbox-range-requests pour la stratégie utilisée en tant que gestionnaire.
  • Les éléments <video> ou <audio> doivent activer le mode CORS avec l'attribut crossorigin.
  • Si vous souhaitez diffuser des contenus multimédias à partir du cache, vous devez les y ajouter explicitement à l'avance. Pour ce faire, vous pouvez effectuer une mise en cache préalable, avec cache.add() ou utiliser la méthode hotStrategyCache dans le fichier "Workbox-recipes". La mise en cache de l'asset multimédia lors de sa diffusion en streaming au moment de l'exécution ne fonctionne pas, car seule une partie du contenu est extraite du réseau pendant la lecture.

Voici comment répondre à ces exigences dans Workbox, en commençant par le balisage approprié pour un asset multimédia:

<!-- 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>

Ensuite, dans votre service worker, utilisez le plug-in workbox-range-request pour gérer les éléments multimédias en conséquence:

// 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(),
    ],
  }),
);

Cette approche vous permet de vous assurer que les éléments multimédias de votre site Web sont correctement récupérés et mis en cache par votre service worker, tout en prenant en compte les requêtes de plage et les autres pièges potentiels liés aux requêtes multimédias.