Що таке 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]]