В Express req.params хранит значения именованных сегментов пути маршрута (/users/:id даёт req.params.id), req.query хранит строку запроса после ? (/search?q=node даёт req.query.q), а req.body хранит данные, отправленные в теле запроса. req.params и req.query заполняются при каждом запросе, а req.body остаётся undefined, пока его не прочитает парсер тела, например app.use(express.json()). Значения в params и query всегда строки.
Первый запрос отвечает {"params":{"userId":"7"},"query":{"sort":"new","limit":"2"}}. Обратите внимание на кавычки: 7 и 2 это строки, поэтому преобразуйте их через Number(), прежде чем считать или сравнивать с числами. Теперь переключите метод на POST, оставьте путь /users/7/posts и отправьте тело {"title": "Hello", "draft": true}: ответ будет 201 с "body":{"title":"Hello","draft":true}, где true настоящий boolean, потому что он пришёл из JSON.
req.params, req.query и req.body
req.params | req.query | req.body | |
|---|---|---|---|
| Откуда | Из пути, /users/:id | Из строки запроса, ?sort=new | Из тела запроса |
| Пример URL или тела | /users/7 | /users?sort=new | {"name": "Ada"} |
| Значение | { id: '7' } | { sort: 'new' } | { name: 'Ada' } |
| Типы | Строки | Строки и массивы строк | Всё, что есть в JSON |
| Что нужно настроить | :name в маршруте | Ничего | app.use(express.json()) |
| Для чего обычно | Какой ресурс | Фильтр, сортировка, страница | Данные для создания или изменения |
У маршрута может быть несколько параметров, и каждое имя становится ключом req.params: /teams/:teamId/members/:memberId даёт оба id. Дефис или точка тоже их разделяют, поэтому /flights/:from-:to превращает /flights/LAX-SFO в { from: 'LAX', to: 'SFO' }.
req.query с повторяющимися и отсутствующими ключами
Ключ, который встречается дважды, становится массивом, а отсутствующий ключ равен undefined, поэтому задавайте опциям значение по умолчанию:
Ответ: {"page":1,"tags":["red","sale"],"raw":{"tag":["red","sale"]}}. Отправьте GET /products?tag=red&page=3, и tags всё равно будет массивом, ["red"], потому что [].concat() превращает в массив и одну строку, и массив. Express 5 разбирает строку запроса простым парсером Node, поэтому ?filter[size]=m даёт ключ "filter[size]", а не вложенный объект; Express 4 делал его вложенным.
req.body нужен express.json()
Node отдаёт тело потоком байтов. express.json() читает его, разбирает и заполняет req.body, но только если у запроса Content-Type: application/json. HTML-формы отправляют application/x-www-form-urlencoded, для этого нужен express.urlencoded().
Отправьте POST /signup с телом {"email": "ada@example.com"}, и вы получите 201 с {"email":"ada@example.com","name":"anonymous"}. Отправьте пустое тело, и получите 400. ?? {} здесь важен: без него деструктуризация undefined выбрасывает TypeError на любом запросе без JSON-тела. Для настоящей проверки формы и типов используйте библиотеку схем, например zod.
req.headers и req.get()
req.headers это объект со всеми заголовками запроса, имена в нижнем регистре. req.get(name) читает один заголовок без учёта регистра, поэтому req.get('Content-Type') и req.get('content-type') возвращают одно и то же. Ещё несколько свойств, которые вам пригодятся:
path равен /whoami, а originalUrl равен /whoami?debug=1. Добавьте в строке запроса заголовок Authorization: Bearer abc и отправьте снова: token станет "Bearer abc". Внутри router'а, подключённого через app.use('/api', router), req.path теряет префикс /api, а req.originalUrl его сохраняет (подключение объясняет статья Маршрутизация в Express).
Частые ошибки
Чтение req.body в GET-запросе. Браузеры и большинство клиентов не отправляют тело с GET. Передавайте опции GET в строке запроса.
Проверка флага из query на истинность. ?admin=false даёт строку 'false', а она truthy, поэтому if (req.query.admin) проходит. Сравнивайте строки: req.query.admin === 'true'.
JSON без заголовка. Клиент, который отправляет JSON как text/plain, получает req.body === undefined. Задайте на клиенте Content-Type: application/json.
Часто задаваемые вопросы
Как получить IP-адрес клиента в Express?
Читайте req.ip. За прокси или балансировщиком это адрес прокси, пока вы не зададите app.set('trust proxy', 1), после чего Express будет читать заголовок X-Forwarded-For.
Как получить полный URL запроса в Express?
req.originalUrl это путь вместе со строкой запроса, как их прислал клиент. Абсолютный URL собирается так: `${req.protocol}://${req.get('host')}${req.originalUrl}`.
Как принимать загрузку файлов в Express?
Файлы приходят как multipart/form-data, а это express.json() и express.urlencoded() не разбирают. Используйте пакет вроде multer, который кладёт файлы в req.file или req.files, а остальные поля в req.body.
Как прочитать cookie из запроса?
Сырой заголовок лежит в req.get('cookie'). Чтобы получить объект в req.cookies, установите пакет cookie-parser и добавьте app.use(cookieParser()).