Middleware в Express.js представляет собой функции промежуточной
обработки, которые получают доступ к объектам запроса
(req), ответа (res) и функции перехода к
следующему обработчику (next). Эти функции формируют
цепочку, через которую проходит каждый HTTP-запрос внутри
приложения.
Каждый middleware может:
req или res;next();next(err).Жизненный цикл запроса в Express строится как последовательность вызовов middleware, что позволяет гибко разделять ответственность между компонентами приложения.
Применяются через app.use() и работают для всех
маршрутов или для маршрутов с указанным префиксом.
app.use((req, res, next) => {
console.log('Запрос:', req.method, req.url);
next();
});
Такие middleware часто используются для логирования, парсинга тела запроса, установки заголовков и других глобальных задач.
Привязываются к конкретным маршрутам и выполняются только при совпадении пути.
app.get('/users', (req, res, next) => {
console.log('Обработка /users');
next();
}, (req, res) => {
res.send('Список пользователей');
});
Подобная структура позволяет разделять обработку на логические этапы внутри одного маршрута.
Middleware, предназначенные для обработки ошибок, отличаются сигнатурой: они принимают четыре аргумента.
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Ошибка сервера');
});
Такие функции активируются только при вызове
next(err).
Express.js предоставляет ряд встроенных middleware:
express.json() — обработка JSON-тела запроса;express.urlencoded() — обработка form-data;express.static() — раздача статических файлов.app.use(express.json());
app.use(express.static('public'));
Экосистема Express активно использует внешние пакеты, которые подключаются как обычные функции middleware.
Примеры типичных задач:
Каждый запрос проходит через цепочку функций, определённую порядком регистрации middleware. Порядок имеет критическое значение: изменение последовательности может радикально изменить поведение приложения.
app.use((req, res, next) => {
console.log('Первый middleware');
next();
});
app.use((req, res, next) => {
console.log('Второй middleware');
next();
});
Если один из middleware не вызывает next() и не
отправляет ответ, дальнейшая обработка останавливается.
Функция next() управляет переходом между middleware.
Основные сценарии:
next() — переход к следующему middleware;next('route') — пропуск оставшихся middleware текущего
маршрута;next(err) — переход к обработчику ошибок.app.use((req, res, next) => {
if (!req.headers.authorization) {
return next('route');
}
next();
});
Middleware тесно связаны с системой маршрутов. Каждый маршрут может рассматриваться как цепочка middleware-функций, выполняемых последовательно.
app.get('/profile',
authMiddleware,
loadUser,
(req, res) => {
res.json(req.user);
}
);
Такой подход позволяет разделять бизнес-логику на независимые этапы.
В современных приложениях часто используются асинхронные операции (работа с базой данных, внешними API). Middleware могут быть асинхронными функциями.
app.use(async (req, res, next) => {
try {
req.user = await getUserFromDB();
next();
} catch (err) {
next(err);
}
});
Важно корректно передавать ошибки в next, иначе они не
попадут в error-handling middleware.
Ошибки в Express распространяются по специальному пути. Как только
вызывается next(err), управление передаётся ближайшему
middleware с четырьмя параметрами.
app.use((req, res, next) => {
throw new Error('Ошибка обработки');
});
app.use((err, req, res, next) => {
res.status(500).json({ message: err.message });
});
Middleware без err-параметра игнорируются при обработке
ошибок.
Порядок регистрации определяет поведение всей системы:
Нарушение порядка приводит к некорректной обработке запросов или невозможности перехвата ошибок.
Middleware проверяет наличие и валидность токена.
function auth(req, res, next) {
if (!req.token) {
return res.status(401).send('Unauthorized');
}
next();
}
Определяет права доступа после аутентификации.
function role(roleName) {
return (req, res, next) => {
if (req.user.role !== roleName) {
return res.status(403).send('Forbidden');
}
next();
};
}
Фиксация всех входящих запросов.
app.use((req, res, next) => {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
next();
});
Middleware может проверять входные данные до передачи в бизнес-логику.
function validateUser(req, res, next) {
if (!req.body.name) {
return res.status(400).send('Name required');
}
next();
}
Middleware можно комбинировать, формируя переиспользуемые цепочки.
const userPipeline = [
auth,
loadUser,
validateUser
];
app.post('/user', userPipeline, (req, res) => {
res.send('OK');
});
Такой подход повышает модульность и упрощает поддержку кода.
Частые проблемы:
next() → зависание запроса;Каждый middleware добавляет накладные расходы. В высоконагруженных системах важно:
app.use((req, res, next) => {
if (req.method !== 'GET') return next();
// лёгкая логика только для GET
next();
});