Обработка больших файлов в сервис-воркере требует особого подхода, так как стандартная стратегия кэширования “cacheFirst” или “networkFirst” может быть неэффективной при передаче больших ресурсов, таких как видео, архивы или ISO-образы. Библиотека Workbox предоставляет возможности для тонкой настройки работы с такими файлами, включая поддержку range-запросов, которые позволяют загружать только часть файла.
HTTP range-запросы позволяют клиенту запрашивать только
фрагмент ресурса, задавая заголовок Range
с диапазоном байт. Это критично для:
Пример заголовка range-запроса:
Range: bytes=0-999
Сервис-воркер должен уметь корректно обрабатывать такие запросы,
чтобы вернуть только запрошенный фрагмент файла с соответствующими
заголовками (Content-Range, Accept-Ranges,
Content-Length).
Workbox предоставляет модуль workbox-range-requests,
который позволяет кэшировать не весь файл целиком, а
отдельные диапазоны, обеспечивая эффективное использование памяти и
диска. Основные концепции:
workbox-strategies, который перехватывает range-запросы и
проверяет наличие соответствующего сегмента в кэше.Пример использования RangeRequestsPlugin с CacheFirst
стратегией:
import { registerRoute } from 'workbox-routing';
import { CacheFirst } from 'workbox-strategies';
import { RangeRequestsPlugin } from 'workbox-range-requests';
import { ExpirationPlugin } from 'workbox-expiration';
registerRoute(
({ request }) => request.destination === 'video',
new CacheFirst({
cacheName: 'video-cache',
plugins: [
new RangeRequestsPlugin(),
new ExpirationPlugin({ maxEntries: 20 })
]
})
);
Ключевые моменты:
RangeRequestsPlugin автоматически разбивает запросы на
сегменты и сохраняет их в кэше.ExpirationPlugin позволяет контролировать количество
сегментов и их срок хранения.NetworkFirst) для потокового контента.При работе с большими файлами важно использовать streaming
API в сервис-воркере. Workbox поддерживает обработку потоков
через fetch и позволяет передавать части файла напрямую
клиенту:
self.addEventListener('fetch', event => {
const range = event.request.headers.get('range');
if (range) {
event.respondWith(handleRangeRequest(event.request));
}
});
async function handleRangeRequest(request) {
const url = new URL(request.url);
const response = await caches.match(url.pathname) || await fetch(request);
const buffer = await response.arrayBuffer();
const [start, end] = parseRangeHeader(request.headers.get('range'), buffer.byteLength);
const slicedBuffer = buffer.slice(start, end + 1);
return new Response(slicedBuffer, {
status: 206,
statusText: 'Partial Content',
headers: [
['Content-Range', `bytes ${start}-${end}/${buffer.byteLength}`],
['Accept-Ranges', 'bytes'],
['Content-Length', slicedBuffer.byteLength]
]
});
}
function parseRangeHeader(range, totalLength) {
const match = /bytes=(\d*)-(\d*)/.exec(range);
const start = match[1] ? parseInt(match[1]) : 0;
const end = match[2] ? parseInt(match[2]) : totalLength - 1;
return [start, end];
}
Особенности реализации:
206 Partial Content для
частичных ответов.Content-Range должен отражать фактический
диапазон и общий размер файла.arrayBuffer() может
быть заменено на потоковое чтение через Response.body для
минимизации потребления памяти.ExpirationPlugin или собственных механизмов удаления старых
сегментов предотвращается переполнение кэша.Workbox и range-запросы особенно актуальны для видео-плееров, которые поддерживают HTTP Live Streaming (HLS) и DASH. В таких случаях:
CacheFirst + RangeRequestsPlugin снижает
нагрузку на сеть и ускоряет повторное воспроизведение.Эти подходы позволяют строить веб-приложения с эффективной обработкой больших файлов, минимизируя потребление ресурсов и улучшая пользовательский опыт при потоковой передаче данных.