Date de publication : 6 octobre 2020
Certaines requêtes HTTP contiennent un en-tête Range:, indiquant que seule une partie de la ressource complète doit être renvoyée. Ils sont couramment utilisés pour diffuser du contenu audio ou vidéo en streaming, ce qui permet de charger à la demande de plus petits blocs de contenu multimédia au lieu de demander l'intégralité du fichier distant en une seule fois.
Un service worker est un code JavaScript qui se situe entre votre application Web et le réseau. Il peut intercepter les requêtes réseau sortantes et générer des réponses pour celles-ci.
Historiquement, les requêtes de plage et les service workers ne fonctionnaient pas bien ensemble. Il a été nécessaire de prendre des mesures spéciales pour éviter des résultats négatifs dans votre service worker. Heureusement, la situation commence à évoluer. Dans les navigateurs qui se comportent correctement, les requêtes de plage "fonctionnent" simplement lorsqu'elles passent par un service worker.
Quel est le problème ?
Prenons l'exemple d'un service worker avec l'écouteur d'événement fetch suivant, qui prend chaque requête entrante et la transmet au réseau :
self.addEventListener('fetch', (event) => {
// The Range: header will not pass through in
// browsers that behave incorrectly.
event.respondWith(fetch(event.request));
});
Dans les navigateurs au comportement incorrect, si event.request incluait un en-tête Range:, cet en-tête était supprimé sans notification. La requête reçue par le serveur distant n'inclura pas du tout Range:. Cela ne "cassera" pas nécessairement quoi que ce soit, car un serveur est techniquement autorisé à renvoyer le corps de réponse complet, avec un code d'état 200, même lorsqu'un en-tête Range: est présent dans la requête d'origine. Mais cela entraînerait le transfert de plus de données que ce qui est strictement nécessaire du point de vue du navigateur.
Les développeurs qui connaissent ce comportement peuvent le contourner en vérifiant explicitement la présence d'un en-tête Range: et en n'appelant pas event.respondWith() si l'un est présent. Le service worker se retire ainsi de la génération de la réponse, et la logique réseau du navigateur par défaut, qui sait comment préserver les requêtes de plage, est utilisée à la place.
self.addEventListener('fetch', (event) => {
// Return without calling event.respondWith()
// if this is a range request.
if (event.request.headers.has('range')) {
return;
}
event.respondWith(fetch(event.request));
});
On peut affirmer sans risque que la plupart des développeurs n'étaient pas conscients de la nécessité de le faire. et pourquoi cela devrait être obligatoire. En fin de compte, cette limitation était due au fait que les navigateurs devaient rattraper les modifications apportées à la spécification sous-jacente, qui ajoutait la prise en charge de cette fonctionnalité.
Quels problèmes ont été résolus ?
Les navigateurs qui se comportent correctement conservent l'en-tête Range: lorsque event.request est transmis à fetch(). Cela signifie que le code du service worker dans mon exemple initial permettra au serveur distant de voir l'en-tête Range:, s'il a été défini par le navigateur :
self.addEventListener('fetch', (event) => {
// The Range: header will pass through in browsers
// that behave correctly.
event.respondWith(fetch(event.request));
});
Le serveur a maintenant la possibilité de gérer correctement la requête de plage et de renvoyer une réponse partielle avec un code d'état 206.
Quels navigateurs se comportent correctement ?
Les versions récentes de Safari disposent de la fonctionnalité appropriée. Chrome et Edge, à partir de la version 87, se comportent également correctement.
En octobre 2020, Firefox n'avait pas encore corrigé ce comportement. Vous devrez peut-être encore en tenir compte lorsque vous déploirez le code de votre service worker en production.
La meilleure façon de vérifier si un navigateur donné a corrigé ce comportement consiste à cocher la ligne "Include range header in network request" (Inclure l'en-tête de plage dans la requête réseau) du tableau de bord des tests de la plate-forme Web.
Qu'en est-il de la diffusion des requêtes de plage à partir du cache ?
Les service workers peuvent faire bien plus que simplement transmettre une requête au réseau. Un cas d'utilisation courant consiste à ajouter des ressources, comme des fichiers audio et vidéo, à un cache local. Un service worker peut ensuite répondre aux requêtes à partir de ce cache, en contournant complètement le réseau.
Tous les navigateurs, y compris Firefox, permettent d'inspecter une requête dans un gestionnaire fetch, de vérifier la présence de l'en-tête Range:, puis de traiter localement la requête avec une réponse 206 provenant d'un cache. Toutefois, le code du service worker permettant d'analyser correctement l'en-tête Range: et de renvoyer uniquement le segment approprié de la réponse complète mise en cache n'est pas trivial.
Heureusement, les développeurs qui souhaitent obtenir de l'aide peuvent se tourner vers Workbox, qui est un ensemble de bibliothèques qui simplifient les cas d'utilisation courants des service workers. workbox-range-request module implémente toute la logique nécessaire pour diffuser des réponses partielles directement à partir du cache. Vous trouverez une recette complète pour ce cas d'utilisation dans la documentation Workbox.