ERR_CONTENT_DECODING_FAILED: диагностика gzip, Brotli и Content-Encoding

Браузер получил ответ, но не смог его распаковать. Проверяем конкретный ресурс без сжатия, с gzip и Brotli и находим слой, который меняет тело или заголовки.

ERR_CONTENT_DECODING_FAILED означает, что браузер не смог декодировать тело ответа, например распаковать gzip или Brotli. Сервер при этом может вернуть 200 OK: успешный HTTP-код ещё не подтверждает, что страницу или скрипт удалось прочитать.

Сначала найдите точный запрос с ошибкой, затем сравните его загрузку без сжатия и со сжатием. Это помогает отделить повреждённый поток или неверный Content-Encoding от общего сбоя сайта, ошибки кэша и проблемы только на устройстве посетителя.

Что именно не удалось прочитать

В документации Chromium эта ошибка относится к декодированию тела ответа. Это сообщение браузера, а не HTTP-статус и не указание на неправильную кодировку русских букв.

Три заголовка отвечают за разные вещи:

  • Accept-Encoding в запросе сообщает, какие способы сжатия принимает клиент.
  • Content-Encoding в ответе описывает преобразования, применённые к телу, например gzip или br.
  • Content-Type описывает тип содержимого; параметр charset относится к кодировке текста.

По RFC 9110, объявленные преобразования должны соответствовать переданному представлению. Если сервер отправил обычный HTML с Content-Encoding: gzip, клиент попытается распаковать несжатые данные и получит ошибку.

1. Найдите первый сбойный ресурс

Откройте инструменты разработчика → Network, включите сохранение журнала и Disable cache, затем перезагрузите страницу. Ищите запрос с ERR_CONTENT_DECODING_FAILED: это может быть документ, CSS, JavaScript или ответ API.

Запишите публичный URL, время и часовой пояс, HTTP-код, Content-Encoding, Content-Type и доступные заголовки кэша, например Age или X-Cache. Сравните тот же адрес в чистом профиле браузера и другой сети; флажок Disable cache сам по себе не исключает перехват ответа service worker.

Если ошибка есть только на одном устройстве, проверьте расширения, локальный прокси и фильтрацию HTTPS по правилам вашей организации. Очистка локального кэша не исправляет серверный дефект.

2. Сравните GET без сжатия и со сжатием

Для проверки нужен GET с чтением тела. HEAD через curl -I показывает заголовки, но не проверяет распаковку; используйте один и тот же конечный публичный URL без паролей и токенов.

В примерах замените адрес на свой ресурс. Команды рассчитаны на терминал Linux или macOS:

~~~bash curl -q -sS --max-time 30 -H 'Accept-Encoding: identity' -D identity.headers -o identity.body 'https://example.com/assets/app.js'

curl -q -sS --max-time 30 --compressed -H 'Accept-Encoding: gzip' -D gzip.headers -o gzip.body 'https://example.com/assets/app.js'

curl -q -sS --max-time 30 --compressed -H 'Accept-Encoding: br' -D br.headers -o br.body 'https://example.com/assets/app.js' ~~~

Проверьте Content-Encoding каждого фактического ответа, текст ошибки curl и код завершения команды. Запрос identity просит ответ без сжатия, но результат всё равно нужно сверить; если получен редирект, сначала найдите конечный URL и повторите сравнение на нём.

По руководству curl, --compressed включает декодирование поддерживаемого сжатия. Сохранённые заголовки при этом остаются исходными: файл gzip.body уже распакован, хотя gzip.headers может содержать Content-Encoding: gzip.

Перед тестом br проверьте curl --version: нужна поддержка Brotli. Ошибка неподдерживаемого алгоритма у локального curl не доказывает поломку сайта.

Как читать результат

  • identity загружается, gzip не декодируется: исследуйте gzip-представление и слой, который его формирует.
  • gzip работает, br не работает: проверьте Brotli, заранее сжатый файл и соответствующий вариант в CDN.
  • Все варианты работают в curl, но браузер выдаёт ошибку: сравните реальные заголовки браузера, сеть, кэш и service worker. Запросы могли получить разные ответы.
  • Передача обрывается и без сжатия: проверьте приложение, прокси и полноту ответа. Для расхождения длины есть отдельный разбор ERR_CONTENT_LENGTH_MISMATCH.

3. Найдите слой, который портит представление

Сопоставьте ответ приложения, reverse proxy и CDN для того же пути и Accept-Encoding. Origin — исходный сервер за CDN; сравнение с ним выполняет администратор через предусмотренный служебный доступ с правильными Host и SNI, без открытия origin наружу.

Проверьте три типичных сценария:

  1. Заголовок не соответствует телу. Приложение или прокси распаковал ответ, но оставил Content-Encoding; либо заранее сжатый файл отдан с неверным обозначением алгоритма.
  2. Неучтённое повторное сжатие. Несколько слоёв преобразуют тело, а заголовок описывает только один из них. Несколько преобразований допустимы при корректном объявлении.
  3. Смешались варианты кэша. Клиент получил тело одной версии и метаданные другой. Сверьте Vary: Accept-Encoding и правила выбора вариантов у вашего CDN; наличие заголовка не гарантирует правильную настройку всей цепочки.

Если origin исправен, а внешний ответ повреждён, исследуйте преобразования и кэш между ними. Подробная методика проверки свежести вынесена в статью об HTTP-кэше через curl.

4. Исправьте причину и проверьте повторную загрузку

Меняйте по одному условию: исправьте заголовки или настройки конкретного слоя, пересоберите повреждённый сжатый файл. Не удаляйте Content-Encoding у действительно сжатого тела: браузеру всё равно нужно знать, как его прочитать.

После исправления удалите только затронутый объект или вариант из CDN-кэша. Проверьте загрузку при холодном и прогретом кэше, с identity, gzip и br, затем убедитесь в браузере, что критичный ресурс используется без ошибки.

Регулярная внешняя проверка в Web-Puls помогает сохранить время и историю симптома, но не заменяет браузерную проверку распаковки и серверные логи. Контроль одного статуса 200 может пропустить такой дефект.

Если слой сбоя остаётся неясным, отправьте заявку на профессиональную поддержку: укажите публичный URL, время, результаты трёх вариантов и недавние изменения сжатия или CDN. Специалист оценит вводные и согласует формат работ; Cookie, Authorization и доступы в описание не добавляйте.

Проверьте свой сайт прямо сейчас

Введите адрес сайта: Web-Puls покажет HTTP-код, время ответа и базовую диагностику. Для постоянного контроля можно подключить мониторинг.

Нужна помощь с диагностикой ошибки?

Опишите симптомы в короткой заявке: URL, код ответа, время появления и что менялось перед сбоем. Специалист поддержки оценит задачу и предложит формат работ.