Тело запроса и ответа
Тело 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-запрос с телом — технически возможно, но игнорируется многими серверами и прокси
Связанные темы
- _MOC Сеть
- Протокол HTTP -- основы
- Content-Type -- типы данных
- Fetch -- headers, mode, credentials
- REST API