Bereichsanfragen in einem Service Worker verarbeiten

Der Service Worker sollte wissen, was zu tun ist, wenn eine Teilantwort angefordert wird.

Einige HTTP-Anfragen enthalten einen Range:-Header, der angibt, dass nur ein Teil der gesamten Ressource zurückgegeben werden soll. Sie werden üblicherweise zum Streamen von Audio- oder Videoinhalten verwendet, damit kleinere Medienblöcke on demand geladen werden können, anstatt die gesamte Remote-Datei auf einmal anzufordern.

Ein Service Worker ist JavaScript-Code, der sich zwischen Ihrer Webanwendung und dem Netzwerk befindet und möglicherweise ausgehende Netzwerkanfragen abfängt und Antworten für sie generiert.

In der Vergangenheit haben Reichweiteanfragen und Service Worker nicht gut zusammen gespielt. Es waren spezielle Maßnahmen erforderlich, um schlechte Ergebnisse bei Ihrem Service Worker zu vermeiden. Zum Glück beginnt sich das zu ändern. In Browsern mit dem richtigen Verhalten funktionieren Bereichsanfragen „einwandfrei“, wenn sie einen Service Worker durchlaufen.

Worin liegt das Problem?

Angenommen, ein Service Worker mit dem folgenden fetch-Event-Listener nimmt jede eingehende Anfrage auf und übergibt sie an das Netzwerk:

self.addEventListener('fetch', (event) => {
  // The Range: header will not pass through in
  // browsers that behave incorrectly.
  event.respondWith(fetch(event.request));
});

Wenn event.request in Browsern mit falschem Verhalten einen Range:-Header enthält, wird dieser ohne Meldung entfernt. Die Anfrage, die vom Remoteserver empfangen wird, enthält Range: überhaupt nicht. Dadurch würde nicht unbedingt etwas „beschädigen“, da ein Server technisch berechtigt ist, den vollständigen Antworttext mit einem 200-Statuscode zurückzugeben, selbst wenn ein Range:-Header in der ursprünglichen Anfrage vorhanden ist. Dies würde jedoch dazu führen, dass mehr Daten übertragen werden, als aus Sicht des Browsers unbedingt erforderlich ist.

Entwickler, denen dieses Verhalten bekannt ist, können dieses Problem umgehen, indem sie explizit nach einem Range:-Header suchen und event.respondWith(), falls vorhanden, nicht aufrufen. Dadurch entfernt sich der Service Worker effektiv aus dem Bild zur Antwortgenerierung, und stattdessen wird die Standard-Netzwerklogik des Browsers verwendet, die Bereichsanfragen erhalten kann.

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));
});

Allerdings war den meisten Entwicklern nicht bewusst, dass dies erforderlich ist. Und es war nicht klar, warum das erforderlich ist. Letztendlich war das darauf zurückzuführen, dass Browser Änderungen an der zugrunde liegenden Spezifikation aufholen mussten, was diese Funktion unterstützt.

Welche Fehler wurden behoben?

Browser, die ein korrektes Verhalten verhalten, behalten den Range:-Header bei, wenn event.request an fetch() übergeben wird. Das bedeutet, dass der Service Worker-Code in meinem ersten Beispiel dem Remoteserver den Range:-Header ermöglicht, wenn er vom Browser festgelegt wurde:

self.addEventListener('fetch', (event) => {
  // The Range: header will pass through in browsers
  // that behave correctly.
  event.respondWith(fetch(event.request));
});

Der Server kann jetzt die Bereichsanfrage richtig verarbeiten und eine Teilantwort mit dem Statuscode 206 zurückgeben.

Welche Browser verhalten sich richtig?

Aktuelle Versionen von Safari haben die richtige Funktion. Chrome und Edge verhalten sich ab Version 87 ebenfalls einwandfrei.

Seit Oktober 2020 ist dieses Problem in Firefox noch nicht behoben. Möglicherweise müssen Sie es berücksichtigen, wenn Sie den Code Ihres Service Workers für die Produktion bereitstellen.

Wenn Sie im Web Platform-Test-Dashboard die Zeile „Bereichsheader in Netzwerkanfrage einschließen“ anklicken, können Sie am besten prüfen, ob dieses Verhalten durch einen bestimmten Browser korrigiert wurde.

Was ist mit der Bereitstellung von Bereichsanfragen aus dem Cache?

Service Worker können viel mehr tun, als nur eine Anfrage an das Netzwerk weiterzuleiten. Ein häufiger Anwendungsfall besteht darin, Ressourcen wie Audio- und Videodateien einem lokalen Cache hinzuzufügen. Ein Service Worker kann dann Anfragen aus diesem Cache ausführen und das Netzwerk vollständig umgehen.

Alle Browser, einschließlich Firefox, unterstützen die Überprüfung einer Anfrage innerhalb eines fetch-Handlers, die Prüfung auf das Vorhandensein des Range:-Headers und die anschließende lokale Ausführung der Anfrage mit einer 206-Antwort aus einem Cache. Der Service Worker-Code, mit dem der Range:-Header ordnungsgemäß geparst und nur das entsprechende Segment der vollständigen im Cache gespeicherten Antwort zurückgegeben wird, ist jedoch nicht einfach.

Entwickler, die Hilfe benötigen, können sich zum Glück der Workbox zuwenden, einer Reihe von Bibliotheken, die häufige Service-Worker-Anwendungsfälle vereinfachen. Der workbox-range-request module implementiert die gesamte Logik, die zur Bereitstellung von Teilantworten direkt aus dem Cache erforderlich ist. Ein vollständiges Rezept für diesen Anwendungsfall finden Sie in der Workbox-Dokumentation.

Das Hero-Image in diesem Beitrag stammt von Natalie Rhea Riggs auf Unsplash.