HLS.js Light Network Error: причины и способы исправления

Ошибка 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

Выполнено: 0 / 5

Шаг 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() вызывается в цикле безрезультатно, логично показать пользователю сообщение о недоступности потока, а не крутить бесконечный перезапуск.

📊 Где чаще всего возникает network error у вашего плеера?
CORS-блокировка от сервера
Истёкший токен в URL потока
Нестабильный интернет у зрителей
Ошибки в моём коде инициализации

Шаг 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(), а полное пересоздание оставить запасным вариантом с ограничением числа попыток.