1. Зачем нужен парсинг тела запроса?
Когда клиент (браузер, мобильное приложение, Postman или fetch-запрос) отправляет данные на сервер методом POST, PUT или PATCH, эти данные обычно помещаются в "тело запроса" (request body). Например, вы заполняете форму регистрации, нажимаете "Отправить" — и браузер шлёт данные на сервер.
Но Express по умолчанию не умеет "читать мысли" и не парсит тело запроса автоматически. Если вы попытаетесь вывести req.body, получите undefined или пустой объект. Почему? Потому что тело запроса — это просто "сырой поток байтов", который нужно разобрать в удобный для работы вид.
Парсинг тела запроса — это процесс превращения этого "сырого потока" в объект JavaScript, с которым удобно работать в обработчиках Express.
Какие бывают типы тела запроса?
В реальных приложениях чаще всего встречаются два формата передачи данных в теле запроса:
- JSON
Современные SPA, мобильные приложения и API любят отправлять данные в формате JSON (application/json). Пример тела запроса:{ "username": "alice", "password": "qwerty" } - x-www-form-urlencoded
Это стандартный формат, который используют обычные HTML-формы при отправке через <form method="POST"> (если не указать enctype). Пример тела запроса:username=alice&password=qwerty
Есть ещё multipart/form-data (для загрузки файлов), но о нём поговорим позже, когда будем разбирать загрузку файлов.
2. Почему Express не парсит тело сам?
Express — это минималистичный фреймворк. Он не парсит тело запроса "по умолчанию", чтобы не тратить ресурсы на ненужную обработку, если ваше приложение этого не требует. Для разбора тела Express использует middleware — специальные функции, которые подключаются к вашему приложению и "ловят" запросы на ранней стадии.
В старых версиях Express (до 4.x) был встроенный middleware bodyParser, но сейчас его основные функции вынесены в отдельные модули и встроены в сам Express.
Middleware для парсинга тела: express.json() и express.urlencoded()
В Express 4.x и выше есть два встроенных middleware для парсинга тела запроса:
- express.json() — для разбора тела в формате JSON.
- express.urlencoded() — для разбора данных, закодированных как x-www-form-urlencoded (обычные HTML-формы).
Как подключить парсеры?
Всё очень просто: достаточно вызвать их как middleware до объявления ваших маршрутов.
const express = require('express');
const app = express();
// Подключаем парсер JSON
app.use(express.json());
// Подключаем парсер для form-urlencoded
app.use(express.urlencoded({ extended: true }));
// Ваши маршруты идут ниже!
Внимание:
Порядок важен! Сначала подключаем парсеры, потом объявляем маршруты.
3. Пример: Получаем JSON из POST-запроса
Давайте разберём классический пример: пользователь отправляет данные регистрации через JSON.
Клиент отправляет такой запрос:
{
"username": "bob",
"email": "bob@example.com"
}
Сервер — код Express:
const express = require('express');
const app = express();
// Подключаем JSON-парсер
app.use(express.json());
app.post('/register', (req, res) => {
// Теперь req.body — это объект с данными!
console.log(req.body);
// { username: 'bob', email: 'bob@example.com' }
// Можно делать что угодно: валидация, запись в базу и т.д.
res.send(`Привет, ${req.body.username}!`);
});
app.listen(3000, () => {
console.log('Сервер запущен на http://localhost:3000');
});
Как проверить?
Можно воспользоваться Postman, curl или fetch в браузере:
curl -X POST http://localhost:3000/register \
-H "Content-Type: application/json" \
-d '{"username":"bob","email":"bob@example.com"}'
4. Пример: Получаем данные из HTML-формы
Если пользователь отправляет данные через обычную HTML-форму (без загрузки файлов):
<form action="/register" method="POST">
<input name="username">
<input name="email">
<button type="submit">Зарегистрироваться</button>
</form>
Тогда браузер отправит данные в формате x-www-form-urlencoded:
username=alice&email=alice@example.com
Сервер — код Express:
const express = require('express');
const app = express();
// Подключаем парсер для form-urlencoded
app.use(express.urlencoded({ extended: true }));
app.post('/register', (req, res) => {
// req.body — объект с данными формы!
console.log(req.body);
// { username: 'alice', email: 'alice@example.com' }
res.send(`Спасибо за регистрацию, ${req.body.username}!`);
});
app.listen(3000, () => {
console.log('Сервер запущен на http://localhost:3000');
});
Как проверить?
Можно отправить форму из браузера или воспользоваться curl:
curl -X POST http://localhost:3000/register \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=alice&email=alice@example.com"
5. Полезные нюансы
Что значит { extended: true }?
В опциях для express.urlencoded() есть параметр extended:
- extended: false — использует встроенный парсер Node.js (ограниченный, только строки и массивы).
- extended: true — использует библиотеку qs, которая умеет парсить вложенные объекты и массивы.
В 99% случаев используйте extended: true — так вы сможете получать сложные структуры из формы, например:
<input name="user[name]" value="Bob">
<input name="user[email]" value="bob@example.com">
Результат в req.body:
{
user: {
name: 'Bob',
email: 'bob@example.com'
}
}
Совмещаем оба парсера: JSON и urlencoded
В реальных приложениях часто нужно поддерживать оба варианта. Просто подключите оба парсера:
const express = require('express');
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// ... ваши маршруты
Express сам разберётся, какой парсер применить, исходя из заголовка Content-Type в запросе клиента.
6. Практика: Развиваем наше мини-приложение
Давайте добавим в наше учебное приложение новый маршрут для добавления задач в список дел (todo list). Мы хотим поддерживать оба варианта: отправку через JSON (например, из fetch) и через HTML-форму.
Серверный код:
const express = require('express');
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Наш массив задач (в памяти)
const todos = [];
// Добавление задачи
app.post('/todos', (req, res) => {
// req.body работает и для JSON, и для формы!
const { title } = req.body;
if (!title) {
return res.status(400).json({ error: 'Не указано название задачи' });
}
const todo = { id: todos.length + 1, title };
todos.push(todo);
res.status(201).json(todo);
});
// Получение всех задач
app.get('/todos', (req, res) => {
res.json(todos);
});
app.listen(3000, () => {
console.log('TODO-сервер запущен на http://localhost:3000');
});
Проверяем через curl:
Через JSON:
curl -X POST http://localhost:3000/todos \
-H "Content-Type: application/json" \
-d '{"title":"Купить хлеб"}'
Через форму:
curl -X POST http://localhost:3000/todos \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "title=Позвонить маме"
7. Типичные ошибки при парсинге тела запроса
Ошибка №1: забыли подключить парсер.
Самая частая ошибка: забыли добавить app.use(express.json()) или app.use(express.urlencoded()), и req.body всегда пустой. Если вы видите undefined или {} вместо ожидаемых данных — проверьте, что парсер подключён!
Ошибка №2: не тот Content-Type у клиента.
Если клиент отправляет JSON, но не указал заголовок Content-Type: application/json, парсер не сработает, и req.body будет пустым. Аналогично с формами: нужен application/x-www-form-urlencoded.
Ошибка №3: неправильный порядок middleware.
Если парсер подключён после маршрутов, он не сработает для этих маршрутов. Всегда подключайте парсеры ДО объявления роутов.
Ошибка №4: забыли про вложенные объекты в формах.
Если используете вложенные поля в форме (например, user[name]), обязательно выставляйте extended: true в express.urlencoded().
Ошибка №5: не обрабатываете ошибку парсинга.
Если клиент отправил некорректный JSON, Express вернёт ошибку 400. Можно добавить обработчик ошибок, чтобы красиво сообщать о проблеме.
Ошибка №6: используете устаревший body-parser.
В старых туториалах часто встречается const bodyParser = require('body-parser'). Сейчас это не нужно — всё уже встроено в Express.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ