Питання 16 · Розділ 6

Що таке Content-Type header?

Сервер повинен знати, як прочитати дані із запиту. Без Content-Type сервер не зрозуміє, як десеріалізувати байти.

Мовні версії: English Russian Ukrainian

Junior Level

Content-Type — це заголовок HTTP, який каже серверу, в якому форматі надсилаються дані.

Приклади:

Content-Type: application/json        — дані у форматі JSON
Content-Type: application/xml         — дані у форматі XML
Content-Type: text/plain              — звичайний текст
Content-Type: multipart/form-data     — форма з файлами

Навіщо це потрібно?

Сервер повинен знати, як прочитати дані із запиту. Без Content-Type сервер не зрозуміє, як десеріалізувати байти.

Приклад запиту:

POST /users
Content-Type: application/json

{"name": "Ivan", "age": 30}

Поширені медіа-типи:

| Тип | Опис | | ———————————– | —————- | | application/json | JSON дані | | application/xml | XML дані | | text/html | HTML сторінка | | multipart/form-data | Форма з файлами | | application/x-www-form-urlencoded | Дані форми |


Middle Level

Content-Type у Spring MVC

За обробку Content-Type відповідають HttpMessageConverter:

  1. Приходить запит із Content-Type: application/json
  2. Spring перебирає конвертери (Jackson, Gson і т.д.)
  3. Метод canRead(clazz, mediaType) повертає true
  4. Запускається читання і маппінг у Java-об’єкт

Безпека і MIME Sniffing

X-Content-Type-Options: nosniff

Браузери іноді намагаються “вгадати” тип контенту, ігноруючи заголовок. MIME Sniffing — механізм браузера: він намагається визначити тип контенту за вмістом, ігноруючи Content-Type. Корисно для зворотної сумісності, але створює XSS-уразливості.

Ризик: Користувач завантажив картинку, яка насправді JavaScript. Браузер може її виконати.

Рішення: Завжди передавайте X-Content-Type-Options: nosniff.

Boundary у Multipart

При multipart/form-data заголовок містить унікальний роздільник:

Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

Цей роздільник використовується для парсингу тіла запиту на окремі частини.

Прикордонні випадки

  • Missing Content-Type: Якщо клієнт не надіслав заголовок — повернути 415 Unsupported Media Type. Не намагайтеся вгадувати тип
  • Custom MIME Types: Для версіонування використовуйте свої типи: application/vnd.mycompany.v1+json

Продуктивність

  • Charset: Для application/json UTF-8 є дефолтним за RFC 8259, тому charset=utf-8 опціональний. Для text/* типів вказання charset обов’язкове, оскільки дефолт — iso-8859-1.
  • Binary Formats: У Highload-системах використовують application/x-protobuf або application/octet-stream — Protobuf зазвичай у 3-10x швидше JSON при парсингу (залежить від розміру payload і мови). Бінарний формат не потребує лексичного розбору, немає парсингу рядків-ключів — числові теги полів.

Senior Level

Коли Content-Type можна не вказувати

GET-запити без тіла, DELETE без тіла. Для запитів з тілом (POST, PUT, PATCH) — обов’язковий.

Процес вибору конвертера

У Spring MVC HttpMessageConverter обирається на основі:

  1. Заголовка Content-Type із запиту
  2. Зареєстрованих конвертерів у додатку
  3. Методу canRead(clazz, mediaType)

Multipart/Related vs Multipart/Form-Data

  • Multipart/Form-Data: Для завантаження файлів через форми
  • Multipart/Related: Якщо потрібно надіслати об’єкт (JSON) і пов’язаний з ним бінарний файл (картинку) в одному запиті. Ефективніше двох окремих запитів

Продуктивність і Highload

  • Charset Overhead: Вказання кодування запобігає спробам проксі перекодувати текст
  • Binary Formats: Protobuf зазвичай у 3-10x швидше JSON при парсингу (залежить від розміру payload і мови). Бінарний формат не потребує лексичного розбору, немає парсингу рядків-ключів — числові теги полів.
  • Multipart/Related: Ефективніше для відправки JSON + бінарний файл в одному запиті

Діагностика

  • Curl Debugging: curl -v -H "Content-Type: application/json" -d '{"key":"val"}' ... — база для налагодження API
  • Postman/Insomnia Pitfalls: Ці інструменти часто додають Content-Type автоматично. При тестуванні “чистого” API вимикайте автозаповнення
  • 415 Unsupported Media Type: Якщо сервер не підтримує надісланий тип — повертайте 415, не намагайтеся вгадати

🎯 Шпаргалка для співбесіди

Обов’язково знати:

  • Content-Type вказує серверу формат даних у тілі запиту: application/json, application/xml, multipart/form-data
  • Для запитів з тілом (POST, PUT, PATCH) Content-Type обов’язковий; для GET/DELETE без тіла — не потрібен
  • У Spring MVC за обробку відповідають HttpMessageConverter (Jackson, Gson і т.д.)
  • X-Content-Type-Options: nosniff запобігає MIME Sniffing і XSS-атакам
  • multipart/form-data використовує boundary-роздільник для парсингу тіла на частини
  • Missing Content-Type → повернути 415 Unsupported Media Type, не вгадувати
  • Binary Formats (Protobuf) у 3-10x швидше JSON при парсингу

Часті уточнюючі запитання:

  • Навіщо потрібен X-Content-Type-Options: nosniff? — Запобігає MIME Sniffing, коли браузер «вгадує» тип і виконує JS
  • Як Spring обирає конвертер? — За Content-Type запиту → перевіряє canRead(clazz, mediaType) → перший підходящий
  • Коли Content-Type можна не вказувати? — Для GET і DELETE без тіла; для POST/PUT/PATCH — обов’язковий
  • Що таке Multipart/Related? — Відправлення JSON + пов’язаного бінарного файлу в одному запиті, ефективніше двох запитів

Червоні прапорці (НЕ говорити):

  • «Content-Type і Accept — одне й те саме» — Content-Type = що надсилаю, Accept = що хочу отримати
  • «Content-Type потрібен для GET-запитів» — GET без тіла не вимагає Content-Type
  • «Сервер може вгадати тип контенту» — потрібно повернути 415, не вгадувати
  • «charset=utf-8 обов’язковий для JSON» — UTF-8 є дефолтним за RFC 8259, опціональний

Пов’язані теми:

  • [[Що таке Accept header]]
  • [[Як організувати версіонування REST API]]
  • [[Що таке REST]]
  • [[Які HTTP статус коди ви знаєте]]
  • [[Що таке RESTful API дизайн]]