Ошибка network error в hls.js (в том числе в облегчённой сборке hls.light.js) означает, что плеер не смог загрузить манифест .m3u8 или видеосегменты .ts по сети — и видео останавливается с событием Hls.Events.ERROR и типом NETWORK_ERROR. Чаще всего виноваты не сами скрипты, а CORS-политика сервера, недоступный URL потока, истёкший токен в ссылке или слишком агрессивные таймауты загрузки.
Хорошая новость: в большинстве случаев проблема решается без переписывания кода плеера — достаточно правильно настроить повторные попытки загрузки, проверить заголовки ответа сервера и убедиться, что манифест отдаётся корректно. Ниже разберём диагностику по шагам: от проверки в DevTools до тонкой настройки конфигурации hls.js.
Что означает ошибка network error в hls.js
Библиотека hls.js реализует воспроизведение HLS-потоков в браузерах через MediaSource Extensions. Она скачивает манифест, затем плейлисты качеств, затем сами сегменты. Любой сбой на этих этапах — таймаут, HTTP-ошибка, блокировка CORS, обрыв соединения — порождает событие с details вида manifestLoadError, levelLoadError или fragLoadError.
Важно различать два поля в объекте ошибки: fatal и details. Фатальная сетевая ошибка останавливает воспроизведение полностью, а нефатальная может быть пережита встроенным механизмом повторов. Сборка hls.light.js отличается от полной только отсутствием поддержки некоторых функций (например, альтернативных аудиодорожек и субтитров в части реализаций), но логика сетевых ошибок у неё та же.
Типичные значения details при сетевых проблемах:
- 🔴
manifestLoadError— не загрузился главный манифест.m3u8; - 🟡
levelLoadError— не удалось получить плейлист конкретного качества; - 🟠
fragLoadError— сегмент видео не скачался или оборвался; - 🔵
manifestLoadTimeOut/fragLoadTimeOut— превышено время ожидания ответа.
Шаг 1. Диагностика через DevTools
Прежде чем менять конфигурацию, откройте вкладку Network в инструментах разработчика браузера и обновите страницу с плеером. Найдите запросы к файлам .m3u8 и .ts и посмотрите их статус-коды. Это сразу сузит круг причин: 403 или 401 указывают на проблему с токеном или правами, 404 — на неверный путь, CORS-ошибка видна в консоли с характерным сообщением, а статус (failed) без кода часто означает обрыв соединения или блокировку браузером.
Обратите внимание и на вкладку Console. Сообщение вида Access to fetch ... has been blocked by CORS policy однозначно говорит, что сервер потока не отдаёт нужные заголовки. А если запросы вообще не появляются в списке — возможно, ошибка в коде инициализации плеера, а не в сети.
Шаг 2. Проверка CORS и заголовков сервера
Самая частая причина network error при встраивании чужого HLS-потока — отсутствие CORS-заголовков. Браузер блокирует кросс-доменные запросы к манифесту и сегментам, если сервер не возвращает заголовок Access-Control-Allow-Origin. При этом в плеере вы увидите просто network error, а настоящая причина видна только в консоли.
Если сервер потока ваш — добавьте в конфигурацию веб-сервера отдачу заголовка Access-Control-Allow-Origin (для домена вашего сайта или *, если это допустимо). Также убедитесь, что для файлов .m3u8 отдаётся корректный MIME-тип application/vnd.apple.mpegurl, а для сегментов — video/mp2t. Неверный MIME-тип не всегда ломает воспроизведение, но в ряде конфигураций приводит к сбоям.
⚠️ Внимание: если поток чужой и сервер не отдаёт CORS-заголовки, исправить это со стороны клиента невозможно. Проксирование потока через собственный сервер — рабочий вариант, но проверьте, что это не нарушает условия использования источника.
Шаг 3. Настройка повторных попыток и таймаутов
Если сеть нестабильна или сервер иногда отвечает медленно, помогает увеличение количества повторных попыток и таймаутов в конфигурации hls.js. За это отвечают параметры manifestLoadingMaxRetry, levelLoadingMaxRetry, fragLoadingMaxRetry и соответствующие таймауты. Пример конфигурации:
const hls = new Hls({
manifestLoadingTimeOut: 10000,
manifestLoadingMaxRetry: 4,
levelLoadingTimeOut: 10000,
levelLoadingMaxRetry: 4,
fragLoadingTimeOut: 20000,
fragLoadingMaxRetry: 6
});
Увеличение fragLoadingMaxRetry особенно полезно для зрителей с нестабильным мобильным интернетом: отдельные сегменты будут перезапрашиваться вместо полной остановки воспроизведения. Однако бесконечные повторы ставить не стоит — если ресурс действительно недоступен, плеер будет бесполезно грузить сеть.
☑️ Базовая проверка при network error
Шаг 4. Обработка фатальных ошибок в коде
Даже с настроенными повторами фатальная ошибка может наступить — и тогда плеер просто встанет. Правильный подход — подписаться на событие ошибки и реализовать восстановление: при сетевой ошибке вызвать hls.startLoad(), при ошибке медиа — hls.recoverMediaError(). Минимальный обработчик выглядит так:
hls.on(Hls.Events.ERROR, function (event, data) {
if (data.fatal) {
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
hls.startLoad();
break;
case Hls.ErrorTypes.MEDIA_ERROR:
hls.recoverMediaError();
break;
default:
hls.destroy();
}
}
});
Такой обработчик превращает большинство временных сбоев в незаметные для зрителя подёргивания. Но добавьте счётчик попыток восстановления: если startLoad() вызывается в цикле безрезультатно, логично показать пользователю сообщение о недоступности потока, а не крутить бесконечный перезапуск.
Шаг 5. Проблемы с токенами и живыми потоками
Многие стриминговые сервисы выдают ссылки на манифест с временным токеном в query-строке. Когда токен истекает, сервер начинает отвечать 403 — и плеер получает manifestLoadError. Для live-трансляций, где манифест перезапрашивается периодически, это классическая ситуация: первые минуты всё работает, потом поток «умирает». Решение — обновлять URL через xhrSetup или пересоздавать плеер с новой ссылкой.
Для живых потоков также проверьте, что манифест действительно обновляется на сервере: если плейлист «заморожен», плеер в какой-то момент не найдёт новых сегментов. Если сегменты отдаются с 404, а манифест при этом обновляется — почти наверняка проблема в рассинхронизации публикации потока на сервере, а не в hls.js.
| Симптом | Вероятная причина | Что делать |
|---|---|---|
| Ошибка сразу при старте | CORS или неверный URL | Проверить консоль и открыть манифест напрямую |
| Поток умирает через время | Истёк токен в ссылке | Обновлять URL через xhrSetup |
| Рывки и остановки | Нестабильная сеть | Увеличить fragLoadingMaxRetry |
| 404 на сегментах | Рассинхрон на сервере | Проверить публикацию потока |
| (failed) без статуса | Обрыв соединения, блокировка | Проверить HTTPS/Mixed Content |
Шаг 6. Mixed Content и версия библиотеки
Если ваш сайт работает по HTTPS, а поток отдаётся по HTTP, браузер заблокирует запросы как Mixed Content — и вы получите network error без внятного статуса. Проверьте, что URL манифеста начинается с https://. Если у источника нет HTTPS-версии, варианты ограничены: проксирование через свой сервер с шифрованием или смена источника потока.
Также убедитесь, что используете актуальную версию hls.js — старые релизы содержали ошибки в логике повторных запросов и обработке редиректов. Обновление через npm или смена ссылки на CDN — безопасный шаг, который стоит сделать до углублённой отладки.
⚠️ Внимание: не отключайте проверку Mixed Content и не ослабляйте CORS глобально в браузере ради отладки на боевом сайте — это создаёт уязвимости. Такие флаги допустимы только в локальной среде разработки.
Как проверить, что ошибка именно в hls.js, а не в потоке
Откройте тот же URL манифеста в нативном HLS-плеере — например, в Safari на macOS или iOS, где HLS поддерживается без библиотек. Если и там поток не играет, проблема на стороне сервера или самого потока. Если в Safari всё работает, а в Chrome с hls.js — нет, копайте в сторону CORS, конфигурации и обработчиков ошибок.
Сводный порядок действий
Соберём всё в краткий алгоритм. Сначала диагностируем, потом чиним — а не наоборот:
- 🔍 Открыть Network в DevTools и посмотреть статусы запросов к
.m3u8и сегментам; - 🌐 Проверить консоль на CORS-ошибки и Mixed Content;
- 🔑 Убедиться, что токен в URL живой, а манифест открывается напрямую;
- ⚙️ Увеличить retry и таймауты в конфигурации hls.js;
- 🛠️ Добавить обработчик
Hls.Events.ERRORсstartLoad()для сетевых ошибок; - 🔄 Обновить библиотеку до актуальной версии.
Частые вопросы
Чем hls.light.js отличается от полной версии при обработке ошибок?
Логика сетевых запросов и событий ошибок в облегчённой сборке та же. Отличия касаются набора поддерживаемых функций (часть возможностей вроде некоторых типов дорожек и субтитров исключена ради размера). Инструкции из этой статьи применимы к обеим сборкам.
Почему ошибка появляется только у части зрителей?
Это типичный признак сетевых проблем на стороне клиента: нестабильный мобильный интернет, блокировки провайдера, корпоративные прокси или VPN. Увеличение fragLoadingMaxRetry и обработчик с автоматическим startLoad() сглаживают большинство таких случаев.
Можно ли исправить CORS-ошибку только на стороне клиента?
Нет. CORS-политика применяется браузером, и обойти её из JavaScript нельзя. Нужны изменения на сервере потока (добавление заголовков) либо проксирование потока через собственный сервер, который будет отдавать корректные заголовки.
Поток работает в Safari, но падает с network error в Chrome. В чём дело?
Safari воспроизводит HLS нативно, без hls.js, и его сетевой стек ведёт себя иначе. Если в Safari всё работает, проверяйте в Chrome консоль на CORS и Mixed Content, а также конфигурацию самой библиотеки — чаще всего причина именно там.
Поможет ли просто пересоздать плеер при ошибке?
Иногда да — вызов hls.destroy() и создание нового экземпляра с тем же URL помогает при «залипших» состояниях. Но это грубый метод: сначала стоит использовать штатные startLoad() и recoverMediaError(), а полное пересоздание оставить запасным вариантом с ограничением числа попыток.