Перейти к основному содержимому

Руководства / Коды состояния HTTP: разбор

406 Not Acceptable: что означает и как исправить

406 Not Acceptable означает, что сервер не может произвести ответ, совпадающий с тем, что клиент заявил как приемлемое. Сам запрос в порядке; провалилось согласование между тем, что было запрошено, и тем, что сервер способен предложить, - обычно по формату, языку или кодированию ответа.

Что означает 406 Not Acceptable

HTTP поддерживает согласование содержимого через семейство заголовков Accept: Accept для типа содержимого ответа, Accept-Language для языка и Accept-Encoding для сжатия. Клиент может отправить любой из них, чтобы сказать "давай мне только тот ответ, который я могу использовать". Согласно RFC 9110, если сервер не может произвести представление, которое клиент указал как приемлемое, и предпочитает сообщить об этом, а не отправить что-то в любом случае, он отвечает 406. На практике большинство серверов молча игнорируют узкий заголовок Accept и отправляют свой ответ по умолчанию вместо этого, поэтому настоящий 406 встречается реже, чем сам заголовок.

Как проявляется ошибка

Браузер редко вызывает 406 при обычной загрузке страниц, поскольку браузеры отправляют разрешительные заголовки Accept, совпадающие почти с чем угодно, что предлагает сервер. Гораздо чаще он появляется у клиентов API, скриптов и инструментов командной строки, задающих строгий заголовок Accept:

curl -i -H "Accept: application/xml" https://api.example.com/v1/status
HTTP/1.1 406 Not Acceptable
Content-Type: application/json

В этом примере клиент запросил только XML, а API может производить только JSON, поэтому сервер отказывает, вместо того чтобы отправить формат, который клиент явно сказал, что не хочет.

Что вызывает 406 Not Acceptable

  • Действительно провалившееся согласование содержимого. Заголовок Accept, Accept-Language или Accept-Encoding, называющий только форматы, которые сервер не может произвести, чаще всего клиент, запрашивающий XML у API, отдающего только JSON, либо конкретный языковой вариант, которого у сервера нет.
  • Web application firewall на общем хостинге. Это очень частая реальная причина, никак не связанная с согласованием содержимого: ModSecurity и похожие правила WAF в средах общего хостинга блокируют запросы, у которых заголовок Accept выглядит необычно, отсутствует либо похож на автоматизированный, и отвечают 406 как ответом блокировки независимо от того, что на самом деле согласовывалось.
  • API, отдающий только JSON, получает запрос от клиента, отправляющего Accept: text/html. Некоторые API строги в этом и отказывают, вместо того чтобы деградировать, что проявляется как 406 для любого клиента, включая вкладку браузера, открытую напрямую на эндпоинте.
  • Неправильно настроенное правило обратного прокси или CDN, проверяющее и отклоняющее по заголовку Accept по причинам кэширования или фильтрации ботов, не связанным с тем, что реально может произвести origin-сервер.
  • Слишком строгая обработка Accept-Encoding. Сервер, настроенный отказывать в любом запросе, не перечисляющем предпочитаемый им метод сжатия, вместо того чтобы откатиться на несжатый ответ.

Как понять, кто виноват

Если только конкретный скрипт или интеграция сталкивается с 406, проверьте, что говорят его заголовки Accept, поскольку суженный или неправильно настроенный заголовок на стороне клиента часто является прямой причиной. Если тот же запрос работает с обычным, разрешительным заголовком Accept, но проваливается с конкретным, сервер действительно не может отдать этот формат. Если это также затрагивает обычный трафик браузеров, либо ошибка началась сразу после изменения хостинга или WAF без изменений кода на вашей стороне, более вероятный виновник - правила безопасности общего хостинга, и быстрее всего это подтвердить, запустив HTTP-проверку из нескольких мест с теми же заголовками, что отправляет ваша интеграция, чтобы понять, стабильна ли блокировка или специфична для одной сети.

Как исправить 406 Not Acceptable

Если вы посетитель

  1. Уберите или ослабьте заголовок Accept в скрипте или инструменте, отправляющем запрос, если вы им управляете, и позвольте ему принимать формат по умолчанию, который предлагает сервер.
  2. Проверьте документацию API на предмет того, какие типы содержимого и языки он поддерживает, прежде чем предполагать, что сервер сломан.
  3. Попробуйте выполнить запрос из браузера напрямую, поскольку браузеры отправляют широкие заголовки Accept и редко сталкиваются с этой ошибкой, что помогает подтвердить, что блокировка специфична именно для заголовков вашего клиента.

Если вы администрируете сайт

  1. Сначала проверьте свои правила ModSecurity или WAF, если 406 неожиданна и широко распространена, поскольку среды общего хостинга часто блокируют по паттернам заголовка Accept, а не из-за настоящего провала согласования. Посмотрите в собственных логах WAF на предмет сработавшего id правила, прежде чем трогать код приложения.
  2. Убедитесь, какие форматы ваш API реально отдает, и либо поддержите больше того, что запрашивают реальные клиенты, либо четко задокументируйте требование, чтобы 406 был информативным, а не неожиданным.
  3. Откатывайтесь к представлению по умолчанию вместо прямого отказа, там где это приемлемо для вашего API, поскольку большинство реальных клиентов лучше обрабатывают "вот JSON, хотя вы спросили широко", чем прямой отказ.
  4. Проверьте правила обратного прокси и CDN на предмет чего-либо, проверяющего заголовок Accept для кэширования или управления ботами, поскольку правило, предназначенное для одной цели, может побочным эффектом давать 406 для несвязанного трафика.

Как предотвратить, чтобы 406 не сломал интеграцию

406, вызванный обновлением безопасности у хостинг-провайдера или новым правилом WAF, не будет выглядеть как сбой изнутри вашей собственной сети, поскольку ваши собственные запросы могут использовать другие заголовки, чем у затронутой интеграции. Плановая HTTP-проверка, отправляющая тот же заголовок Accept, что используют ваши реальные клиенты, с проверкой ожидаемого кода состояния, ловит провал согласования в момент, когда он начинается. Проверка из нескольких мест также помогает отделить правило WAF на весь хостинг от того, что применяется только на определенных edge-узлах.

Похожие ошибки

См. 403 Forbidden - для тесно связанного случая, когда правило WAF или бота блокирует запрос напрямую, а не из-за согласования содержимого, обзор 4xx - для более широкого семейства, и 413 Payload Too Large в других руководствах этой партии.

Часто задаваемые вопросы

Это то же самое, что ошибка CORS?

Нет. Сбои CORS происходят потому, что браузер отказывается показывать межисточниковый ответ вызывающему скрипту; 406 - это сам сервер отказывается производить тело ответа вообще, потому что не может удовлетворить запрошенный формат, язык или кодирование.

Почему я вижу 406 только от curl или Postman, никогда от браузера?

Браузеры по умолчанию отправляют широкие, разрешительные заголовки Accept. Инструменты вроде curl ничего не отправляют либо отправляют узкий заголовок, если вы не зададите его явно, что гораздо вероятнее вызывает настоящий провал согласования либо срабатывание правила WAF, настроенного помечать необычные заголовки.

Может ли ModSecurity дать 406, даже если мой заголовок Accept совершенно нормальный?

Да. Многие наборы правил ModSecurity на общем хостинге помечают запросы как автоматизированные на основе сочетания сигналов, включая точную структуру и порядок заголовков Accept, и отвечают 406 как общим ответом блокировки, а не потому что согласование содержимого действительно провалилось.

Должен ли мой API возвращать 406 или просто откатываться на JSON по умолчанию?

Откат на разумный формат более дружелюбен к реальным клиентам и именно так поступает большинство продакшн-API. Возврат 406 оправдан, когда молчаливая отдача неверного формата активно вводила бы вызывающего в заблуждение.

В чем разница между 406 и 415?

406 - о том, что клиент может принять в ответе. 415 Unsupported Media Type - о том, что сервер может принять в теле запроса, отправленном клиентом. Они охватывают противоположные направления одной и той же идеи согласования.

Проверить сейчас

Запустите бесплатную проверку своего сайта - аккаунт не нужен.

HTTP check

Следить за этим постоянно

Получайте оповещение в момент сбоя: HostTracker проверяет более чем из 300 локаций и уведомляет по email, SMS, в Slack, Telegram и не только.

Возможности HostTracker

Ещё в этом разделе: Коды состояния HTTP: разбор