Що таке Content-Type header
Мережевий протокол передає тіло повідомлення як потік «сирих» байтів. Заголовок Content-Type пояснює одержувачу, за якими правилами та яким парсером ці байти слід інтерпретувати:
🟢 Junior Level
Content-Type — це заголовок сутності (Entity Header) протоколу HTTP (RFC 9110, розділ 8.3), що вказує клієнту або серверу тип даних (Media Type / MIME Type), переданих у тілі (body) HTTP-запиту або відповіді.
Принцип роботи
Мережевий протокол передає тіло повідомлення як потік «сирих» байтів. Заголовок Content-Type пояснює одержувачу, за якими правилами та яким парсером ці байти слід інтерпретувати:
POST /api/v1/users HTTP/1.1
Content-Type: application/json; charset=utf-8
{"name": "Ivan", "age": 30}
Без цього заголовка сервер не знає: перед ним звичайний текст, JSON-документ, XML чи бінарний PDF-файл.
Різниця між Content-Type та Accept
Content-Type: Описує формат даних, які відправник надсилає прямо зараз у поточному тілі запиту/відповіді.Accept: Описує формати даних, які відправник готовий прийняти у відповідному повідомленні.
Найбільш поширені медіа-типи (MIME types)
| MIME Type | Призначення |
|---|---|
application/json |
Стандарт де-факто для REST API (RFC 8259). |
application/xml |
Документи у форматі XML. |
application/x-www-form-urlencoded |
Стандартні HTML-форми (пари key=value&key2=val2). |
multipart/form-data |
Завантаження файлів та складених даних (з boundary). |
text/plain / text/html |
Звичайний текст або HTML-сторінки. |
application/octet-stream |
Довільні бінарні дані (байти). |
🟡 Middle Level
Механіка вибору HttpMessageConverter у Spring MVC
У Spring MVC за читання тіла запиту з урахуванням Content-Type відповідає ланцюжок інтерфейсів HttpMessageConverter<T>:
HTTP Request (Content-Type: application/json)
│
▼
DispatcherServlet
│
▼
RequestResponseBodyMethodProcessor
│
┌────────────────┴────────────────┐
▼ ▼
MappingJackson2HttpMessageConverter ByteArrayHttpMessageConverter
- canRead(UserDto.class, JSON) -> TRUE - canRead(...) -> FALSE
│
▼
objectMapper.readValue(stream, UserDto.class)
- Spring перебирає список зареєстрованих конвертерів у порядку пріоритету.
- Для кожного конвертера викликається метод
canRead(targetClass, mediaType). - Перший конвертер, який повернув
true(наприклад,MappingJackson2HttpMessageConverter), читаєInputStreamі здійснює десеріалізацію. - Якщо відповідний конвертер не знайдено — Spring генерує
HttpMediaTypeNotSupportedException, що трансформується у статус415 Unsupported Media Type.
Атрибут consumes у Spring контролерах
За допомогою анотацій @PostMapping / @PutMapping можна явно обмежити підтримувані формати:
@PostMapping(value = "/upload", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Void> processJson(@RequestBody UserDto dto) { ... }
Якщо клієнт надішле запит із Content-Type: application/xml, Spring MVC поверне 415 Unsupported Media Type ще до входу в метод контролера.
Параметри заголовка: charset та boundary
charset=utf-8: За специфікацією RFC 8259 дляapplication/jsonкодування UTF-8 є обов’язковим стандартом за замовчуванням, тому передачаcharsetдля JSON є надлишковою. Дляtext/plainабоtext/htmlзазначенняcharsetкритично важливе, інакше браузер застосує застарілийISO-8859-1.boundaryуmultipart/form-data:Content-Type: multipart/form-data; boundary=---------------------------974767299852498929531610575Роздільник
boundaryгенерується клієнтом і розмежовує частини складеного запиту (текстові поля форми та потоки байтів завантажуваних файлів).
Безпека: MIME Sniffing та захист X-Content-Type-Options: nosniff
Історично браузери намагалися «вгадати» справжній формат файлу за його вмістом (magic bytes), ігноруючи надісланий сервером Content-Type. Це призводило до вразливостей Cross-Site Scripting (XSS):
- Зловмисник завантажував аватарку з розширенням
.png, всередині якої сховано тег<script>alert('XSS')</script>. - Сервер віддавав файл як
Content-Type: image/png. - Браузер користувача виконував «sniffing», вирішував, що це HTML/JavaScript, і виконував шкідливий код.
Захист: Сервер завжди зобов’язаний надсилати заголовок відповіді:
X-Content-Type-Options: nosniff
Цей заголовок забороняє браузеру змінювати тип контенту, гарантуючи сувору інтерпретацію.
🔴 Senior Level
Спеціалізовані MIME типи в Enterprise REST
У зрілих архітектурах застосовуються вузькоспеціалізовані медіа-типи:
application/problem+json(RFC 9457): Стандарт структури помилок (Problem Details), прийнятий за замовчуванням у Spring Boot 3.application/merge-patch+json(RFC 7386): Сигналізує про часткове оновлення через злиття JSON-структур у методіPATCH.application/json-patch+json(RFC 6902): Масив атомарних інструкційadd,remove,replace.application/vnd.company.user.v2+json(Vendor-specific MIME): Ізольоване версіонування схеми через Content Negotiation.
Високопродуктивні бінарні формати
У Highload-системах та міжсервісних комунікаціях заміна JSON на бінарні формати дає економію мережевого трафіку в 3–5 разів та прискорення парсингу в 5–10 разів (за рахунок відсутності лексичного розбору рядків):
application/x-protobuf(Google Protocol Buffers)application/avro(Apache Avro)application/cbor(Concise Binary Object Representation)
Реалізація підтримки складених форматів у Spring Boot 3
Приклад контролера, що підтримує завантаження файлу разом із метаданими через multipart/form-data та JSON:
package com.example.controller;
import com.example.dto.DocumentMetadataDto;
import com.example.service.DocumentService;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
@RestController
@RequestMapping("/api/v1/documents")
public class DocumentUploadController {
private final DocumentService documentService;
public DocumentUploadController(DocumentService documentService) {
this.documentService = documentService;
}
// Приймає multipart/form-data: частину метаданих у JSON та бінарний файл
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Void> uploadDocument(
@RequestPart("metadata") DocumentMetadataDto metadata,
@RequestPart("file") MultipartFile file) throws IOException {
// Перевіряємо валідність Content-Type завантажуваного файлу
String fileContentType = file.getContentType();
if (fileContentType == null || !fileContentType.equals(MediaType.APPLICATION_PDF_VALUE)) {
return ResponseEntity.status(HttpStatus.UNSUPPORTED_MEDIA_TYPE).build();
}
documentService.save(metadata, file.getBytes());
return ResponseEntity.status(HttpStatus.CREATED).build();
}
}
🎯 Шпаргалка для інтерв’ю
30-секундна відповідь
Content-Type(RFC 9110) — це HTTP-заголовок, що вказує MIME-тип даних, які містяться в тілі поточного запиту або відповіді. Він необхідний одержувачу (серверу або клієнту) для вибору правильного десеріалізатора/парсера (наприклад, Jackson дляapplication/json).На відміну від
Accept(який повідомляє, який формат клієнт очікує у відповіді),Content-Typeповідомляє, який формат передається прямо зараз.У Spring MVC заголовок обробляється через
HttpMessageConverterта атрибутconsumes. Якщо надіслано непідтримуваний тип контенту, сервер зобов’язаний повернути помилку415 Unsupported Media Type.
4 каверзних питання з відповідями
-
Який код HTTP-відповіді має повернути сервер, якщо клієнт надіслав тіло у форматі XML, а сервер приймає лише JSON? Відповідь: Сервер зобов’язаний повернути статус
415 Unsupported Media Type. Повернення помилки 400 Bad Request у такій ситуації є порушенням стандарту HTTP. -
Навіщо в заголовок
multipart/form-dataдодається параметрboundary? Відповідь: Параметрboundaryвизначає унікальну послідовність символів (роздільник), яка слугує межею між окремими частинами складеного HTTP-запиту (наприклад, між JSON-метаданими та бінарним потоком байтів завантажуваного файлу). -
Чи обов’язково вказувати
charset=utf-8дляapplication/json? Відповідь: Ні, за специфікацією RFC 8259 кодування UTF-8 є суворим стандартом за замовчуванням для формату JSON, тому параметрcharsetє надлишковим. Проте для типівtext/plainтаtext/htmlзазначення кодування обов’язкове. -
Що таке MIME Sniffing і для чого потрібен заголовок
X-Content-Type-Options: nosniff? Відповідь: MIME Sniffing — це механізм браузерів, що намагається перевизначити оголошений серверомContent-Type, аналізуючи байти вмісту. Зловмисники використовують це для XSS-атак (маскуючи виконуваний JavaScript під картинку). Заголовокnosniffзмушує браузер суворо довіряти переданомуContent-Type.
Червоні прапорці (чого категорично не можна говорити)
- ❌ «Content-Type і Accept — це одне й те саме» (
Content-Typeописує тіло, що надсилається,Acceptзапитує формат відповіді). - ❌ «GET-запити обов’язково повинні містити Content-Type: application/json» (запити без тіла повідомлення не повинні містити заголовок
Content-Type). - ❌ «Якщо клієнт надіслав непідтримуваний тип даних, сервер повинен вгадати формат самостійно» (сервер зобов’язаний повернути
415 Unsupported Media Type). - ❌ «Заголовок X-Content-Type-Options: nosniff потрібен для оптимізації швидкості парсингу JSON» (він потрібен виключно для безпеки проти XSS-атак).