@budarin/psw-plugin-serve-range-requests
v1.0.41
Published
Service Worker plugin for @budarin/pluggable-serviceworker that serves HTTP Range requests for cached files
Downloads
790
Maintainers
Readme
@budarin/psw-plugin-serve-range-requests
Плагин Service Worker для @budarin/pluggable-serviceworker, который обслуживает HTTP Range запросы для кэшированных файлов.
Если медиа кэшируется без поддержки Range-запросов, браузер вынужден загружать файл целиком в память и воспроизводить его с начала до конца. Перейти к другому месту (перемотка) при этом нельзя, а для больших файлов объём занятой памяти получается очень большим. На слабых или ограниченных по памяти устройствах это нередко приводит к подвисаниям, сбоям воспроизведения или даже падениям. Плагин добавляет корректную поддержку Range для кэшированного контента: читаются и отдаются только запрошенные диапазоны байтов, поэтому перемотка работает, а потребление памяти остаётся приемлемым.
Зачем нужен этот плагин
Приложения для воспроизведения и просмотра больших медиафайлов обычно запрашивают данные по частям (HTTP Range), а не целиком. Если такие файлы лежат в обычном кеше, на каждый запрос одного сегмента из кеша будет извлекаться и передаваться клиенту весь файл — лишняя нагрузка на память и процессор, из‑за которой приложение может тормозить. Плагин отдаёт из кеша только запрошенный диапазон байтов, поэтому воспроизведение остаётся плавным, а потребление ресурсов — умеренным.
Быстрый старт
В большинстве случаев достаточно выбрать готовый пресет и указать имя кеша. Остальные опции можно не трогать.
import { initServiceWorker } from '@budarin/pluggable-serviceworker';
import {
serveRangeRequests,
VIDEO_PRESET,
} from '@budarin/psw-plugin-serve-range-requests';
initServiceWorker(
[serveRangeRequests({ ...VIDEO_PRESET, cacheName: 'video-cache' })],
{ version: '1.0.0' }
);Минимальный вариант без пресета — только обязательный параметр:
serveRangeRequests({ cacheName: 'media-cache' });Подробнее по сценариям (видео, карты, документы) — ниже. Все опции — в конце раздела.
Плагин обрабатывает только GET-запросы с заголовком Range, подходящие под фильтры include/exclude (если они заданы). Для каждого такого range-запроса плагин сам возвращает ответ: либо 206 из кэша (из полного файла или из кэша диапазонов), либо ответ из сети — при промахе кэша, при обходе бага Chromium (уже отдавали этот URL из сети в этой вкладке) или при наличии у клиента If-Range. Остальные запросы — без Range, не GET или не прошедшие фильтры — плагин не обрабатывает и передаёт следующим плагинам в цепочке.
Когда что кешировать — по сценариям
Плагин кеширует два типа данных: метаданные файлов (размер, тип) и готовые ответы по диапазонам. Но смысл кеширования диапазонов сильно зависит от того, как пользователь работает с контентом.
Видео и аудио: при перемотке кеш диапазонов не используется
При перемотке каждый переход (seek) запрашивает новый участок файла. Пользователь редко возвращается к тому же байтовому диапазону — плеер запрашивает другие смещения. Кеш диапазонов почти не попадает в повторные запросы и только занимает память.
Для видео и аудио ставьте maxCachedRanges в 0. Важнее: при перемотке браузер шлёт десятки запросов и отменяет старые. С prioritizeLatestRequest: true плагин отдаёт приоритет последнему запросу и отменяет лишнюю работу.
Документы (PDF и т.п.): кеш полезен при листании
Пользователь листает туда-сюда — одни и те же страницы запрашиваются повторно. Кеш диапазонов помогает. prioritizeLatestRequest: false — без очередей, все запросы параллельно.
Карты и тайлы: кеш очень полезен
При панорамировании и зуме запрашиваются одни и те же тайлы снова и снова. Один и тот же диапазон в pmtiles/mbtiles запрашивается многократно — кеш диапазонов даёт заметный выигрыш. Ставьте maxCachedRanges побольше (500–1000). prioritizeLatestRequest: false — без очередей, все запросы параллельно.
Кеш диапазонов (maxCachedRanges, maxCacheableRangeSize)
Плагин кеширует готовые ответы по диапазонам и метаданные файлов (размер, тип) для тех же URL. maxCachedRanges ограничивает, сколько ответов и записей метаданных держать. maxCacheableRangeSize — верхняя граница на один диапазон; диапазоны крупнее не кешируются (защита от переполнения). Для видео и аудио при перемотках ставьте maxCachedRanges в 0 — кеш не используется.
Параллелизм (maxConcurrentRangesPerUrl)
Действует только при prioritizeLatestRequest: true. Для видео и аудио оптимально 1 — очереди тормозят. При false ограничение не применяется — все запросы параллельно.
Приоритет последнего запроса (prioritizeLatestRequest)
true (по умолчанию) — для видео и аудио: приоритет последнему запросу, отмена лишних при новом. false — для карт и документов: без очередей, все запросы выполняются параллельно.
Ответы 206 и кеш браузера
По умолчанию плагин не выставляет заголовок Cache-Control для ответов 206. Чтобы разрешить кеширование в браузере, задайте rangeResponseCacheControl (например 'max-age=31536000, immutable'). Чтобы запретить кеширование — 'no-store'. Если опцию не задавать, заголовок не отправляется.
Для настройки ориентируйтесь на реальные запросы — смотрите Network в DevTools.
Все опции
Опции сгруппированы по смыслу. Значения по умолчанию подходят для большинства сценариев.
Основное
| Параметр | Тип | По умолчанию | Описание |
| ----------- | -------- | ------------ | ---------------------------------------- |
| cacheName | string | — | Обязательно. Имя кеша. |
| order | number | -10 | Опционально. Порядок выполнения плагина. |
Кеш диапазонов и память
| Параметр | Тип | По умолчанию | Описание |
| ----------------------- | -------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| maxCachedRanges | number | 100 | Макс. число закешированных ответов по диапазонам (и записей метаданных). Для видео при перемотке обычно 0. Для карт/документов — 500–1000. |
| maxCacheableRangeSize | number | 10MB | Макс. размер одного кешируемого диапазона; большие не кешируются. |
| maxTrackedUrls | number | 512 | Максимум разных файлов (URL), по которым плагин учитывает ограничение одновременных запросов. Ограничивает рост памяти при большом числе файлов. |
Параллелизм и приоритет
| Параметр | Тип | По умолчанию | Описание |
| --------------------------- | --------- | ------------ | ---------------------------------------------------------------------- |
| maxConcurrentRangesPerUrl | number | 4 | Сколько диапазонов одного файла читать параллельно. Для видео часто 1. |
| prioritizeLatestRequest | boolean | true | Приоритет последнему запросу (видео/аудио). false — карты/документы. |
Фильтры
| Параметр | Тип | По умолчанию | Описание |
| --------- | ---------- | ------------ | --------------------------------------------- |
| include | string[] | — | Маски файлов (glob). Только эти обрабатывать. |
| exclude | string[] | — | Маски файлов (glob). Исключить из обработки. |
Восстановление и отдача
| Параметр | Тип | По умолчанию | Описание |
| --------------------------- | ---------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| restoreMissingToCache | boolean | true | При отсутствии файла в кеше: отдать запрос из сети и в фоне загрузить полный файл в кеш для следующих запросов. |
| assets | string[] | — | Пути к ресурсам (например /assets/Meeting.mp4), не полные URL — при сборке домен неизвестен. Если список задан: фоновое восстановление в кеш только для запросов, путь которых входит в этот список. |
| rangeResponseCacheControl | string | — | Необязательный Cache-Control для ответов 206 (например 'max-age=31536000, immutable' для кеширования в браузере). Если не задан, заголовок не отправляется. |
Отладка
| Параметр | Тип | По умолчанию | Описание |
| --------------- | --------- | ------------ | --------------- |
| enableLogging | boolean | false | Подробные логи. |
Важные моменты
⚠️ Не кешируйте огромные файлы и диапазоны — мобильные устройства могут не справиться с ними. Данные диапазона читаются из потока кешированного файла последовательно (Cache API не поддерживает произвольный доступ), поэтому запрос диапазона в конце очень большого файла может выполняться долго; предпочтительны более мелкие ресурсы.
Один источник на URL в рамках вкладки (обход бага Chromium) — В Chromium при смене источника в середине воспроизведения (сначала сеть, затем ответы из кэша SW) медиа-пайплайн игнорирует ответ из кэша и воспроизведение падает с PIPELINE_ERROR_READ. Поэтому плагин для каждого URL в рамках вкладки не переключает источник: если по этому URL в этой вкладке уже отдавали из сети (например, файла не было в кэше), все последующие запросы по этому URL в той же вкладке идут в сеть до перезагрузки страницы, даже когда файл уже восстановлен в кэш. После перезагрузки при наличии файла в кэше отдача идёт из кэша. Подробнее: Chromium bug #1026867, тест-кейс phoboslab.
Пример использования
С пресетами (рекомендуется):
import { initServiceWorker } from '@budarin/pluggable-serviceworker';
import {
serveRangeRequests,
VIDEO_PRESET,
AUDIO_PRESET,
} from '@budarin/psw-plugin-serve-range-requests';
initServiceWorker(
[
serveRangeRequests({ ...VIDEO_PRESET, cacheName: 'video-cache' }),
serveRangeRequests({ ...AUDIO_PRESET, cacheName: 'audio-cache' }),
],
{ version: '1.0.0' }
);Ручная настройка (если нужно подкрутить под себя):
serveRangeRequests({
cacheName: 'media-cache',
include: ['*.mp4', '*.webm', '*.mkv'],
maxCachedRanges: 0,
maxConcurrentRangesPerUrl: 1,
prioritizeLatestRequest: true,
});Готовые пресеты (опционально)
Если не хотите настраивать параметры вручную, используйте готовые пресеты:
Доступные пресеты
- VIDEO_PRESET – для медиаплееров:
*.mp4,*.webm,*.mkv,*.avi,*.mov,*.m4v - AUDIO_PRESET – для аудиоплееров:
*.mp3,*.flac,*.wav,*.m4a,*.ogg,*.aac - MAPS_PRESET – для карт и тайлов:
*.mbtiles,*.pmtiles,/tiles/*,/maps/*,*.mvt - DOCS_PRESET – для документов:
*.pdf,*.epub,*.djvu,*.mobi,*.azw3
Адаптивные пресеты
Все пресеты можно адаптировать под характеристики устройства. На устройствах с малым объёмом памяти и слабым процессором лимиты автоматически снижаются.
import { getAdaptivePresets } from '@budarin/psw-plugin-serve-range-requests';
const { VIDEO_ADAPTIVE, AUDIO_ADAPTIVE, MAPS_ADAPTIVE, DOCS_ADAPTIVE } =
getAdaptivePresets();
// Использовать так же: { ...VIDEO_ADAPTIVE, cacheName: 'video-cache' }Поддерживаемые Range форматы
bytes=0-499— первые 500 байтовbytes=500-999— байты с 500 по 999bytes=500-— от 500 байта до концаbytes=-500— последние 500 байтов
Как это работает
- Проверяет заголовок Range в запросе
- Ищет файл в указанном кеше
- Если файл есть в кеше: плагин отдаёт из кэша только когда для этой вкладки и URL источник не меняется; иначе запрос передаётся в сеть (обход бага Chromium #1026867).
- При отсутствии файла плагин отдаёт запрос из сети и при
restoreMissingToCache: trueв фоне загружает полный файл в кеш для следующих запросов только если путь запроса входит вassets(еслиassetsзадан; иначе — для любого URL). В этой вкладке все последующие запросы по этому URL идут в сеть до перезагрузки страницы. - Читает нужный диапазон из файла и возвращает HTTP 206 (Partial Content). При включённом кешировании диапазонов ответ сохраняется для повторного использования.
🤝 License
MIT © budarin
