Bereichsanfragen in einem Service Worker verarbeiten

Stellen Sie sicher, dass Ihr Service Worker weiß, was zu tun ist, wenn eine Teilantwort angefordert wird.

Einige HTTP-Anfragen enthalten einen Range:-Header, der angibt, dass nur ein Teil der vollständigen Ressource zurückgegeben werden soll. Sie werden häufig zum Streamen von Audio- oder Videoinhalten verwendet, um kleinere Medienblöcke auf Abruf zu laden, anstatt die gesamte Remotedatei auf einmal anzufordern.

Ein Service Worker ist JavaScript-Code, der zwischen Ihrer Webanwendung und dem Netzwerk liegt und möglicherweise ausgehende Netzwerkanfragen abfängt und Antworten darauf generiert.

Bisher funktionierten Bereichsanfragen und Service Worker nicht gut zusammen. Es waren spezielle Maßnahmen erforderlich, um negative Auswirkungen auf Ihren Service Worker zu vermeiden. Glücklicherweise ändert sich das langsam. In Browsern, die das richtige Verhalten zeigen, funktionieren Bereichsanfragen einfach, wenn sie einen Service Worker passieren.

Worin liegt das Problem?

Angenommen, Sie haben einen Service Worker mit dem folgenden fetch-Ereignislistener, der jede eingehende Anfrage an das Netzwerk weiterleitet:

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

In Browsern mit dem falschen Verhalten wird der Range:-Header, der in event.request enthalten ist, stillschweigend gelöscht. Die Anfrage, die vom Remote-Server empfangen wurde, enthält Range: überhaupt nicht. Dies würde nicht unbedingt zu Problemen führen, da ein Server technisch den vollständigen Antworttext mit einem 200-Statuscode zurückgeben darf, auch wenn in der ursprünglichen Anfrage ein Range:-Header vorhanden ist. Dies würde jedoch dazu führen, dass mehr Daten übertragen werden, als aus Sicht des Browsers unbedingt erforderlich sind.

Entwickler, denen dieses Verhalten bekannt war, können das Problem umgehen, indem sie explizit auf das Vorhandensein eines Range:-Headers prüfen und nicht event.respondWith() aufrufen, sofern vorhanden. Dadurch entfernt sich der Service Worker effektiv aus dem Antwortgenerierungsabbild und stattdessen wird die Standardnetzwerklogik des Browsers verwendet, die weiß, wie Bereichsanfragen beibehalten werden.

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

Die meisten Entwickler wussten jedoch nicht, dass dies notwendig ist. Dabei war nicht klar, warum das erforderlich sein sollte. Diese Einschränkung war letztendlich darauf zurückzuführen, dass Browser die Änderungen an der zugrunde liegenden Spezifikation nachholen mussten, durch die diese Funktion unterstützt wurde.

Welche Fehler wurden behoben?

Browser mit korrektem Verhalten behalten den Range:-Header bei, wenn event.request an fetch() übergeben wird. Das bedeutet, dass der Dienstworker-Code in meinem ersten Beispiel dem Remote-Server den Range:-Header anzeigt, 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 nun die Bereichsanfrage ordnungsgemäß verarbeiten und eine Teilantwort mit dem Statuscode 206 zurückgeben.

Bei welchen Browsern funktioniert das korrekt?

In den neuesten Versionen von Safari ist die Funktion korrekt. Chrome und Edge verhalten sich ab Version 87 ebenfalls ordnungsgemäß.

Stand Oktober 2020 wurde dieses Problem in Firefox noch nicht behoben. Daher müssen Sie es möglicherweise berücksichtigen, wenn Sie den Code Ihres Dienstarbeiters in der Produktion bereitstellen.

Wenn Sie im Dashboard für Webplattform-Tests die Zeile „Bereichsheader in Netzwerkanfrage einschließen“ aktivieren, lässt sich am besten feststellen, ob dieses Verhalten in einem bestimmten Browser behoben wurde.

Wie sieht es mit dem Bereitstellen von Bereichsanfragen aus dem Cache aus?

Service Worker können viel mehr tun, als nur eine Anfrage an das Netzwerk weiterzuleiten. Ein häufiger Anwendungsfall ist das Hinzufügen von Ressourcen wie Audio- und Videodateien zu einem lokalen Cache. Ein Service Worker kann dann Anfragen aus diesem Cache bearbeiten, ohne das Netzwerk zu nutzen.

Alle Browser, einschließlich Firefox, unterstützen die Prüfung einer Anfrage in einem fetch-Handler, die Prüfung auf Vorhandensein des Range:-Headers und die lokale Ausführung der Anfrage mit einer 206-Antwort aus einem Cache. Der Service Worker-Code zum korrekten Parsen des Range:-Headers und zum Zurückgeben nur des entsprechenden Segments der vollständigen im Cache gespeicherten Antwort ist jedoch nicht trivial.

Glücklicherweise können Entwickler, die Hilfe benötigen, Workbox verwenden. Dabei handelt es sich um eine Reihe von Bibliotheken, die gängige Anwendungsfälle für Service Worker vereinfachen. Die workbox-range-request module implementiert die gesamte Logik, die zum Bereitstellen von Teilantworten direkt aus dem Cache erforderlich ist. Eine vollständige Anleitung für diesen Anwendungsfall finden Sie in der Workbox-Dokumentation.

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