Убедитесь, что ваш сервисный работник знает, что делать, когда запрашивается частичный ответ.
Некоторые HTTP-запросы содержат заголовок Range:
:, указывающий, что должна быть возвращена только часть полного ресурса. Они обычно используются для потоковой передачи аудио- или видеоконтента, чтобы обеспечить загрузку небольших фрагментов мультимедиа по требованию вместо того, чтобы запрашивать весь удаленный файл сразу.
Сервис-воркер — это код JavaScript, который находится между вашим веб-приложением и сетью, потенциально перехватывая исходящие сетевые запросы и генерируя на них ответы.
Исторически сложилось так, что запросы диапазона и сервисные работники не очень хорошо взаимодействовали друг с другом. Было необходимо принять специальные меры, чтобы избежать плохих результатов для вашего сервис-воркера. К счастью, ситуация начинает меняться. В браузерах, демонстрирующих правильное поведение, запросы диапазона будут «просто работать» при прохождении через сервис-воркера.
В чем проблема?
Рассмотрим сервис-воркера со следующим прослушивателем событий fetch
, который принимает каждый входящий запрос и передает его в сеть:
self.addEventListener('fetch', (event) => {
// The Range: header will not pass through in
// browsers that behave incorrectly.
event.respondWith(fetch(event.request));
});
В браузерах с неправильным поведением, если event.request
включал заголовок Range:
этот заголовок автоматически удалялся. Запрос, полученный удаленным сервером, вообще не будет включать Range:
Это не обязательно что-либо «сломает», поскольку серверу технически разрешено возвращать полное тело ответа с кодом состояния 200
, даже если в исходном запросе присутствует заголовок Range:
Но это приведет к передаче большего количества данных, чем это строго необходимо с точки зрения браузера.
Разработчики, которые знали об этом поведении, могли обойти это, явно проверив наличие заголовка Range:
и не вызывая event.respondWith()
, если он присутствует. Сделав это, сервис-воркер фактически удаляет себя из картины формирования ответа и вместо этого используется сетевая логика браузера по умолчанию, которая знает, как сохранять запросы диапазона.
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));
});
Однако можно с уверенностью сказать, что большинство разработчиков не осознавали необходимости этого. И было непонятно, зачем это нужно. В конечном счете, это ограничение было связано с тем, что браузерам нужно было успевать за изменениями в базовой спецификации , которая добавляла поддержку этой функциональности.
Что исправлено?
Браузеры, которые ведут себя правильно, сохраняют заголовок Range:
при передаче event.request
в fetch()
. Это означает, что код сервисного работника в моем первоначальном примере позволит удаленному серверу видеть заголовок Range:
если он был установлен браузером:
self.addEventListener('fetch', (event) => {
// The Range: header will pass through in browsers
// that behave correctly.
event.respondWith(fetch(event.request));
});
Теперь сервер получает возможность правильно обработать запрос диапазона и вернуть частичный ответ с кодом состояния 206
.
Какие браузеры ведут себя корректно?
Последние версии Safari имеют правильную функциональность . Chrome и Edge, начиная с версии 87 , также ведут себя корректно.
По состоянию на октябрь 2020 года Firefox еще не исправил это поведение, поэтому вам все равно придется учитывать его при развертывании кода вашего сервис-воркера в рабочей среде.
Проверка строки «Включить заголовок диапазона в сетевой запрос» на панели инструментов «Тесты веб-платформы» — лучший способ проверить, исправил ли данный браузер это поведение.
А как насчет обслуживания запросов диапазона из кеша?
Сервисные работники могут сделать гораздо больше, чем просто передать запрос в сеть. Распространенным вариантом использования является добавление ресурсов, таких как аудио- и видеофайлы, в локальный кеш . Затем сервисный работник может выполнять запросы из этого кэша, полностью минуя сеть.
Все браузеры, включая Firefox, поддерживают проверку запроса внутри обработчика fetch
, проверку наличия заголовка Range:
а затем локальное выполнение запроса с ответом 206
, поступающим из кеша. Однако код сервисного работника для правильного анализа заголовка Range:
и возврата только соответствующего сегмента полного кэшированного ответа не является тривиальным.
К счастью, разработчики, которым нужна помощь, могут обратиться к Workbox , который представляет собой набор библиотек, упрощающий типичные сценарии использования сервис-воркеров. workbox-range-request module
реализует всю логику, необходимую для обслуживания частичных ответов непосредственно из кеша. Полный рецепт этого варианта использования можно найти в документации Workbox .
Изображение героя в этом посте создано Натали Реей Риггс на Unsplash.