Opublikowano: 6 października 2020 r.
Niektóre żądania HTTP zawierają nagłówek Range:, który wskazuje, że powinna zostać zwrócona tylko część pełnego zasobu. Są one powszechnie używane do strumieniowego przesyłania treści audio lub wideo, aby umożliwić ładowanie mniejszych fragmentów multimediów na żądanie, zamiast jednoczesnego pobierania całego pliku zdalnego.
Skrypt service worker to kod JavaScript, który znajduje się między aplikacją internetową a siecią. Może on przechwytywać wychodzące żądania sieciowe i generować dla nich odpowiedzi.
Żądania zakresu i skrypty service worker nie zawsze dobrze ze sobą współpracowały. Konieczne było podjęcie specjalnych kroków, aby uniknąć niepożądanych wyników w przypadku skryptu service worker. Na szczęście zaczyna się to zmieniać. W przeglądarkach, które działają prawidłowo, żądania zakresu będą „po prostu działać” po przejściu przez skrypt service worker.
Na czym polega problem?
Rozważmy skrypt service worker z tym detektorem zdarzeń fetch, który przyjmuje każde przychodzące żądanie i przekazuje je do sieci:
self.addEventListener('fetch', (event) => {
// The Range: header will not pass through in
// browsers that behave incorrectly.
event.respondWith(fetch(event.request));
});
W przeglądarkach, w których występuje to nieprawidłowe działanie, jeśli event.request zawierał nagłówek Range:, nagłówek ten byłby cicho odrzucany. Żądanie, które otrzyma zdalny serwer, nie będzie w ogóle zawierać Range:. Nie musi to niczego „psuć”, ponieważ serwer technicznie może zwrócić pełną treść odpowiedzi z 200 kodem stanu, nawet jeśli w pierwotnym żądaniu występuje nagłówek Range:. Spowoduje to jednak przesłanie większej ilości danych, niż jest to bezwzględnie konieczne z perspektywy przeglądarki.
Deweloperzy, którzy znają to zachowanie, mogą je obejść, sprawdzając, czy występuje nagłówek Range:, i nie wywołując funkcji event.respondWith(), jeśli jest on obecny. W ten sposób skrypt service worker skutecznie usuwa się z procesu generowania odpowiedzi, a zamiast niego używana jest domyślna logika sieciowa przeglądarki, która wie, jak zachować żądania zakresu.
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));
});
Można śmiało powiedzieć, że większość deweloperów nie zdawała sobie sprawy z konieczności wykonania tej czynności. Nie było jasne, dlaczego jest to wymagane. Ograniczenie to wynikało z konieczności dostosowania przeglądarek do zmian w specyfikacji, które wprowadziły obsługę tej funkcji.
Co zostało naprawione?
Przeglądarki, które działają prawidłowo, zachowują nagłówek Range:, gdy do funkcji fetch() przekazywana jest wartość event.request. Oznacza to, że kod skryptu service worker w moim początkowym przykładzie umożliwi serwerowi zdalnemu zobaczenie nagłówka Range:, jeśli został on ustawiony przez przeglądarkę:
self.addEventListener('fetch', (event) => {
// The Range: header will pass through in browsers
// that behave correctly.
event.respondWith(fetch(event.request));
});
Serwer ma teraz możliwość prawidłowego obsłużenia żądania zakresu i zwrócenia odpowiedzi częściowej z 206.
Które przeglądarki działają prawidłowo?
W najnowszych wersjach Safari działa ona prawidłowo. Chrome i Edge od wersji 87 również działają prawidłowo.
W październiku 2020 r. Firefox nie naprawił jeszcze tego zachowania, więc podczas wdrażania kodu skryptu service worker w środowisku produkcyjnym nadal musisz brać to pod uwagę.
Najlepszym sposobem na sprawdzenie, czy dana przeglądarka poprawiła to zachowanie, jest sprawdzenie wiersza „Include range header in network request” (Uwzględnij nagłówek zakresu w żądaniu sieciowym) w panelu testów platformy internetowej.
A co z obsługą żądań zakresu z pamięci podręcznej?
Service workerzy mogą robić znacznie więcej niż tylko przekazywać żądania do sieci. Częstym przypadkiem użycia jest dodawanie zasobów, takich jak pliki audio i wideo, do lokalnej pamięci podręcznej. Skrypt service worker może następnie realizować żądania z tej pamięci podręcznej, całkowicie pomijając sieć.
Wszystkie przeglądarki, w tym Firefox, obsługują sprawdzanie żądania w ramach procedury obsługi fetch, sprawdzanie obecności nagłówka Range:, a następnie lokalne realizowanie żądania za pomocą 206 odpowiedzi pochodzącej z pamięci podręcznej. Kod skryptu service worker, który prawidłowo analizuje nagłówek Range: i zwraca tylko odpowiedni segment pełnej odpowiedzi z pamięci podręcznej, nie jest jednak prosty.
Na szczęście deweloperzy, którzy potrzebują pomocy, mogą skorzystać z Workbox, czyli zestawu bibliotek, które upraszczają typowe przypadki użycia skryptów service worker. workbox-range-request module implementuje całą logikę niezbędną do obsługi odpowiedzi częściowych bezpośrednio z pamięci podręcznej. Pełną instrukcję dotyczącą tego zastosowania znajdziesz w dokumentacji Workbox.