Что такое Accept header?
Сервер вернёт 406 Not Acceptable — "Я не могу ответить в формате, который вы просите".
Junior Level
Accept — это заголовок HTTP, который говорит серверу, в каком формате клиент хочет получить ответ.
Примеры:
Accept: application/json — хочу JSON
Accept: application/xml — хочу XML
Accept: text/html — хочу HTML
Accept: */* — подойдёт любой формат
Разница с Content-Type:
- Content-Type — формат данных, которые отправляю
- Accept — формат данных, которые хочу получить
Пример запроса:
GET /users/1
Accept: application/json
// Ответ сервера:
{"id": 1, "name": "Ivan", "age": 30}
Что будет, если сервер не поддерживает запрошенный формат?
Сервер вернёт 406 Not Acceptable — “Я не могу ответить в формате, который вы просите”.
Middle Level
Content Negotiation в Spring
Алгоритм согласования контента:
- Клиент присылает
Accept: application/json - Spring ищет методы контроллера с
produces = "application/json" - Проверяет наличие
HttpMessageConverter, который может записать (write) данный тип - Если совпадений нет — возвращается 406 Not Acceptable
Коэффициенты качества (q-values)
Заголовок Accept поддерживает веса приоритетов:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
text/html— приоритет1.0(по умолчанию)application/xml— приоритет0.9*/*(всё остальное) —0.8- В примере выше
*/*имеет q=0.8 — это значение конкретного браузера. Клиент может задать любой q от 0.0 до 1.0.
- В примере выше
Зачем? Это позволяет реализовать Graceful Degradation (постепенная деградация — если сервер не может отдать предпочтительный формат, он отдаст альтернативный). Мобильное приложение просит application/json;q=1.0 и text/plain;q=0.5.
Производительность и Кэширование
The Vary Header
Если эндпоинт отдаёт разные форматы (JSON/XML) на один URL в зависимости от Accept, RFC 7231 требует возвращать Vary: Accept, если контент зависит от этого заголовка и ответ может быть кеширован. Без Vary CDN/прокси могут отдать неправильный формат.
Почему? Чтобы кэш (Nginx/CDN) не отдал JSON-ответ пользователю, запросившему XML.
Edge Cases
- Accept-Charset и Accept-Encoding: Не путайте их.
Accept— про формат данных,Accept-Charset— про кодировку,Accept-Encoding— про сжатие (gzip/brotli) - Браузерные Wildcards: Браузеры часто присылают
Accept: */*. Spring выберет первый подходящий конвертер (обычно JSON)
Диагностика
- 406 Not Acceptable Analysis: Всплеск 406 = клиент просит формат, который вы не реализовали (или случайно удалили конвертер)
- ContentNegotiationManager: Можно настроить приоритет: расширение в пути (
.json) → параметр (?format=json) → заголовокAccept. На Senior-уровне рекомендуется полагаться только на заголовки
Senior Level
Когда Accept header не нужен
- API с одним фиксированным форматом (только JSON)
- Внутренние микросервисы — формат зафиксирован контрактом
- Когда Content Negotiation добавляет оверхед без пользы
Content Negotiation — глубокий взгляд
Content Negotiation — это процесс, при котором сервер определяет лучший формат ответа для клиента.
Spring ContentNegotiationManager
Можно настроить приоритет выбора:
- Расширение в пути (
.json) - Параметр запроса (
?format=json) - Заголовок
Accept
Рекомендация: На Senior-уровне полагайтесь только на заголовки. Расширения в пути и параметры запроса создают проблемы с кэшированием и семантикой URL.
Vendor MIME Types для версионирования
Использование application/vnd.mycompany.v1+json — отличный способ версионирования:
- Позволяет кэшировать разные версии API по одному URI
- Если кэш учитывает заголовок
Accept, разные версии не перемешаются
Производительность
- Vary: Accept рекомендуется при поддержке нескольких форматов — без этого CDN может отдать неверный формат из кэша
- Vendor MIME Types позволяют версионировать каждую сущность независимо
- Negative Caching: CDN может кешировать 406 ответы, защищая бэкенд от повторных запросов неподдерживаемых форматов
Диагностика и Мониторинг
- 406 Analysis: Всплеск 406 означает, что клиент обновился и просит формат, который вы ещё не реализовали
- Converter Order: Порядок регистрации конвертеров важен — Spring выбирает первый подходящий
- Browser Behavior: Браузеры часто шлют
Accept: */*, что может привести к неожиданному выбору формата. Тестируйте с реальными User-Agent заголовками
🎯 Шпаргалка для интервью
Обязательно знать:
- Accept указывает серверу формат, в котором клиент хочет получить ответ:
application/json,application/xml - Content-Type = что отправляю, Accept = что хочу получить
- q-values (коэффициенты качества):
Accept: application/json;q=1.0,text/plain;q=0.5— приоритеты от 0.0 до 1.0 - 406 Not Acceptable — сервер не поддерживает запрошенный формат
- Vary: Accept обязателен при поддержке нескольких форматов — без него CDN отдаст неверный формат из кэша
- Vendor MIME Types (
application/vnd.mycompany.v1+json) — способ версионирования API - Spring ContentNegotiationManager: приоритет — расширение пути → query-параметр → заголовок Accept
Частые уточняющие вопросы:
- Что делает Vary: Accept? — Указывает кэшу, что ответ зависит от заголовка Accept; без Vary CDN отдаст JSON вместо XML
- Зачем нужны q-values? — Graceful Degradation: если сервер не может отдать приоритетный формат, отдаст альтернативный
- Почему не стоит использовать расширения (.json) для Content Negotiation? — Создают проблемы с кэшированием и семантикой URL
- Как версионировать через Accept? — Vendor MIME Types:
application/vnd.myapi.v2+json, кэш учитывает Accept
Красные флаги (НЕ говорить):
- «Accept и Content-Type — одно и то же» — Accept = ожидаемый ответ, Content-Type = формат запроса
- «Браузеры всегда шлют конкретный Accept» — браузеры часто шлют
Accept: */* - «406 — это ошибка сервера» — 406 = клиент просит формат, который сервер не поддерживает
- «Vary: Accept не нужен» — без Vary CDN может отдать JSON-ответ клиенту, запросившему XML
Связанные темы:
- [[Что такое Content-Type header]]
- [[Как организовать версионирование REST API]]
- [[Какие HTTP статус коды вы знаете]]
- [[Что такое REST]]
- [[Что такое HATEOAS]]