Что такое middleware в Express.js и как его подключить?
Что такое middleware в Express
Middleware (промежуточное ПО) — это функция вида (req, res, next) => {}, которая получает доступ к объекту запроса req, объекту ответа res и функции next. Express обрабатывает каждый HTTP-запрос через цепочку таких функций, подключённых в определённом порядке.
Middleware может:
- читать и изменять
reqиres(например, парсить тело запроса, добавлять поля); - завершать цикл запрос-ответ, отправив ответ через
res.send()илиres.json(); - передать управление следующему middleware, вызвав
next(); - передать ошибку дальше, вызвав
next(err).
Если ни ответ не отправлен, ни next() не вызван — запрос "зависнет" и клиент не получит ответ до таймаута.
Виды middleware
- Application-level — подключаются через
app.use()илиapp.get/post/...(). - Router-level — то же самое, но на экземпляре
express.Router(). - Встроенные —
express.json(),express.urlencoded(),express.static(). - Сторонние —
cors,helmet,morgan,cookie-parserи другие, устанавливаются через npm. - Обработчики ошибок — функции с четырьмя аргументами
(err, req, res, next), подключаются в самом конце цепочки.
Как подключить
Глобально, для всех запросов:
app.use(express.json());
Для конкретного префикса пути:
app.use('/api', apiLogger);
Для конкретного маршрута, можно указать несколько подряд:
app.get('/profile', checkAuth, loadUser, handler);
На уровне роутера:
const router = express.Router();
router.use(checkAuth);
app.use('/admin', router);
Порядок выполнения
Express вызывает middleware строго в порядке их подключения. Поэтому:
- глобальные middleware (логирование, парсинг тела запроса) обычно ставят в начале;
- middleware авторизации — перед защищёнными маршрутами;
- обработчики ошибок — всегда последними, после всех роутов.
Обработка ошибок
Если у функции четыре параметра, Express распознаёт её как обработчик ошибок и вызывает только через next(err), минуя обычные middleware. Синхронные ошибки в обработчиках Express перехватывает автоматически, а для асинхронных операций (промисы, async/await) нужно вызывать next(err) вручную — иначе ошибка "потеряется" и запрос зависнет.
Что хочет услышать интервьюер
Понимание сигнатуры middleware и роли next()
Знание видов middleware: application-level, router-level, built-in, третьесторонние, error-handling
Понимание, что порядок подключения определяет порядок выполнения
Умение подключать middleware глобально, для пути и для конкретного маршрута
Знание особенностей обработчика ошибок: 4 аргумента и next(err)
Пример: Простой middleware и его подключение через app.use
const express = require('express');
const app = express();
// middleware для логирования запроса
function logger(req, res, next) {
console.log(`${req.method} ${req.url}`);
next(); // передаём управление дальше по цепочке
}
app.use(logger); // подключаем глобально для всех запросов
app.use(express.json()); // встроенный middleware для парсинга JSON-тела
app.get('/users', (req, res) => {
res.json([{ id: 1, name: 'Anna' }]);
});
app.listen(3000);
Пример: Middleware для конкретного пути и обработчик ошибок
const express = require('express');
const app = express();
function checkAuth(req, res, next) {
if (!req.headers.authorization) {
// завершаем цикл запрос-ответ, next() не вызываем
return res.status(401).json({ error: 'Не авторизован' });
}
next();
}
// middleware применяется только к маршрутам, начинающимся с /admin
app.use('/admin', checkAuth);
app.get('/admin/dashboard', (req, res) => {
res.send('Панель администратора');
});
// обработчик ошибок — обязательно 4 аргумента, подключается последним
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Внутренняя ошибка сервера' });
});
app.listen(3000);
Типичные ошибки
Забывают вызвать next(), из-за чего запрос зависает без ответа
Путают порядок подключения — например, ставят обработчик ошибок не в конце цепочки
Не знают, что error-handling middleware должен иметь ровно 4 аргумента, иначе Express его не распознает
Отправляют res.send() и потом всё равно вызывают next(), что приводит к ошибке 'headers already sent'
Не передают ошибки из асинхронного кода в next(err) вручную, из-за чего они теряются


