Что такое 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-атак).