Ошибка 406 Not Acceptable в API: как проверить заголовок Accept

Ошибка 406 обычно указывает на конфликт между Accept клиента и форматом ответа API. Разбираем запрос по шагам и находим слой, который вернул отказ.

Код 406 Not Acceptable означает: сервер получил запрос, но не нашёл вариант ответа, который соответствует ограничениям клиента. Для API сначала сравните заголовок Accept в запросе с форматами, которые endpoint действительно умеет возвращать.

Быстрая проверка — повторить один и тот же запрос без Accept, затем с Accept: */* и с нужным типом, например application/json. Если первые варианты проходят, а точный тип даёт 406, конфликт почти наверняка находится в согласовании формата ответа.

Что именно сообщает ошибка 406

Accept описывает формат ответа, который готов обработать клиент. Content-Type описывает формат уже передаваемого тела: в запросе — что клиент отправил серверу, в ответе — что сервер вернул клиенту.

Поэтому 406 и 415 решают разные задачи:

  • 406 Not Acceptable — сервер не выбрал приемлемое представление ответа;
  • 415 Unsupported Media Type — сервер не принимает формат тела запроса или его кодирование.

Не меняйте Content-Type наугад, если ошибка зависит от Accept. Так можно скрыть исходный признак и получить новую проблему с разбором тела.

Как воспроизвести 406 без клиентского приложения

Сначала сохраните метод, полный публичный URL, цепочку перенаправлений и безопасный набор заголовков исходного запроса. Не копируйте в заметки токены, Cookie и другие секреты.

Для GET-запроса начните с трёх сравнений:

curl -i https://example.com/api/resource
curl -i -H 'Accept: */*' https://example.com/api/resource
curl -i -H 'Accept: application/json' https://example.com/api/resource

Это диагностический пример, а не готовая команда для закрытого API. Авторизацию проверяйте только в разрешённой тестовой среде и не передавайте секреты в историю терминала.

Если 406 воспроизводится, меняйте за один запуск только один параметр. Иначе вы не поймёте, помогло значение Accept, другой метод, редирект или новая авторизация.

Порядок диагностики

1. Посмотрите фактический Accept

Проверьте запрос в Network браузера, журнале клиента или безопасном trace-логе. Важна строка после всех настроек библиотеки и прокси: SDK может добавить свой Accept поверх значения приложения.

Сравните её с документацией endpoint. Частый конфликт — клиент требует application/xml или vendor-тип вида application/vnd.example.v2+json, а маршрут формирует только application/json.

2. Проверьте веса и запреты

В Accept клиент может перечислить несколько типов с параметром q. Чем больше значение, тем выше приоритет; q=0 означает, что этот вариант неприемлем.

Проверьте и маски. Значение application/* допускает подтипы внутри application, а */* снимает ограничение по типу. Используйте широкую маску только для диагностики: постоянный клиент должен явно понимать формат ответа.

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

Посмотрите контракт API, настройки сериализатора и успешный ответ того же маршрута. Зафиксируйте его Content-Type, а не только расширение URL или ожидаемый формат.

Стандарт HTTP рекомендует серверу сообщать доступные варианты в ответе 406, но полагаться на это нельзя: приложение или промежуточный слой может вернуть лишь короткое сообщение. Тогда сопоставьте запрос со временем события в журналах приложения и прокси.

4. Отделите приложение от промежуточного слоя

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

Сравните тело и заголовки ответа с шаблонами каждого слоя, затем найдите тот же запрос по безопасному идентификатору и времени. Если до приложения запись не дошла, проверяйте правила шлюза; если дошла — выбор формата в маршруте и сериализаторе.

5. Проверьте другие заголовки согласования

Если Accept совпадает с контрактом, отдельно повторите тесты для Accept-Language и Accept-Encoding. Не отключайте всё одновременно: так вы потеряете причинную связь.

Для ответов, которые реально меняются по заголовкам запроса, проверьте Vary. Например, при выборе формата по Accept кэш не должен отдавать одно представление клиентам с несовместимыми предпочтениями.

Где исправлять конфликт

Исправление зависит от нарушенной стороны контракта:

  • в клиенте — если он запрашивает формат, которого endpoint не обещает;
  • в API — если заявленный формат поддерживается в документации, но маршрут его не формирует;
  • в шлюзе или прокси — если заголовок удаляется, переписывается либо запрос блокирует отдельное правило;
  • в кэше — если варианты ответа смешиваются из-за неверного ключа или Vary.

Не заменяйте 406 ответом 200 с неподходящим Content-Type. Клиент может принять статус, но неверно разобрать данные — ошибка станет менее заметной и опаснее.

Как не допустить повторения

Добавьте контрактный тест на каждую обещанную пару «Accept → Content-Type». Отдельно проверьте неизвестный тип, допустимую маску и случай, где все варианты имеют q=0.

После релиза контролируйте не только HTTP-статус, но и ожидаемый тип ответа и минимальный признак корректного тела. В статье про мониторинг API разобрано, какие endpoint выбирать для регулярной проверки.

Web-Puls уместен для контроля доступности публичного health endpoint. Но обычная проверка URL не заменяет контрактный тест с конкретным Accept, авторизацией и данными вашего клиента.

Что передать на диагностику

Если 406 повторяется в production, а источник ответа неясен, можно отправить заявку на профессиональную поддержку. Укажите публичный URL без секретных параметров, метод, время и часовой пояс, безопасные значения Accept и Content-Type, фрагмент ответа и недавние изменения в клиенте, API или прокси.

Этого набора достаточно, чтобы начать с воспроизведения и определить слой отказа. Доступы, Cookie и токены в заявку добавлять не нужно; формат работ и стоимость согласуются до начала.

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

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

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

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