Тело запроса и ответа

Тело HTTP-запроса (request body) и ответа (response body) — произвольные данные, передаваемые после заголовков и отделённые от них пустой строкой.

Зачем нужно

Заголовки несут метаданные, URL — адрес ресурса, а тело — полезная нагрузка: JSON с данными, файл, HTML-страница. Понимание форматов тела и соответствующих заголовков Content-Type и Accept необходимо для корректной отправки и разбора запросов/ответов.

Где используется

  • POST/PUT/PATCH запросы с данными для создания/обновления
  • GET-ответы с данными (JSON, HTML, файлы)
  • Загрузка файлов (multipart/form-data)
  • Streaming-ответы (SSE, chunked transfer encoding)

Тело запроса

JSON (самый распространённый)

POST /api/users HTTP/1.1
Content-Type: application/json
Content-Length: 47

{"name":"Антон","email":"anton@example.com"}
// Отправка JSON через fetch
const res = await fetch('/api/users', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: 'Антон', email: 'anton@example.com' }),
});

Form URL-encoded

POST /api/login HTTP/1.1
Content-Type: application/x-www-form-urlencoded

email=anton%40example.com&password=secret123
const body = new URLSearchParams({ email: 'anton@example.com', password: 'secret123' });
await fetch('/api/login', { method: 'POST', body });

Multipart (файлы)

POST /api/upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----boundary

------boundary
Content-Disposition: form-data; name="file"; filename="photo.jpg"
Content-Type: image/jpeg

<binary data>
------boundary
Content-Disposition: form-data; name="description"

Мой аватар
------boundary--
const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('description', 'Мой аватар');
// Content-Type с boundary выставляется автоматически
await fetch('/api/upload', { method: 'POST', body: formData });

Тело ответа

// Чтение тела ответа — только один раз (поток можно прочитать один раз)
const res = await fetch('/api/users');

// JSON
const users = await res.json();

// Текст (HTML, CSV, XML)
const text = await res.text();

// Бинарные данные (файлы)
const blob = await res.blob();
const url = URL.createObjectURL(blob); // для отображения

// ArrayBuffer (низкоуровневая работа)
const buffer = await res.arrayBuffer();

// Streaming — частичное чтение
const reader = res.body.getReader();
while (true) {
  const { done, value } = await reader.read;
  if (done) break;
  process(value); // Uint8Array
}

Разбор тела на сервере (Express)

const express = require('express');
const app = express;

// JSON
app.use(express.json({ limit: '10mb' }));

// URL-encoded формы
app.use(express.urlencoded({ extended: true }));

// Multipart — через multer
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
app.post('/api/upload', upload.single('file'), (req, res) => {
  console.log(req.file);  // информация о файле
  console.log(req.body);  // остальные поля формы
  res.json({ ok: true });
});

app.post('/api/users', (req, res) => {
  const { name, email } = req.body; // распарсено middleware
  // ...
});

Частые ошибки

  • Читают тело дважды — await res.json после await res.text() вернёт ошибку (поток закрыт)
  • Не указывают Content-Type при отправке JSON — req.body пустой на сервере
  • Передают огромные файлы без лимитов — DoS уязвимость
  • GET-запрос с телом — технически возможно, но игнорируется многими серверами и прокси

Связанные темы

Ресурсы