Что такое порядок middleware в Express.js?

«Что такое порядок middleware в Express.js?» — вопрос из категории Express, который задают на 26% собеседований Node.js Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Порядок middleware в Express.js — это последовательность, в которой функции-обработчики выполняются для входящего HTTP-запроса. Порядок определяется исключительно порядком их регистрации в коде приложения. Это критически важно, так как каждый middleware может модифицировать объекты req и res, выполнять побочные эффекты (логирование, аутентификацию) или завершать цикл обработки.

Базовый пример:

const express = require('express');
const app = express();

// 1. Первым выполняется этот глобальный middleware (например, для логирования)
app.use((req, res, next) => {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
  next(); // Передача управления следующему middleware
});

// 2. Затем выполняется парсинг тела запроса в JSON
app.use(express.json());

// 3. Проверка аутентификации ДО доступа к защищенным маршрутам
app.use('/api', (req, res, next) => {
  const token = req.headers['authorization'];
  if (!isValidToken(token)) {
    return res.status(401).send('Unauthorized'); // Цепочка прерывается
  }
  req.user = decodeToken(token);
  next();
});

// 4. И только потом обрабатывается сам маршрут
app.get('/api/data', (req, res) => {
  res.json({ data: 'Protected data for user ' + req.user.id });
});

// 5. Middleware для обработки ошибок регистрируется ПОСЛЕ всех маршрутов
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

Ключевые правила:

  • next(): Вызов этой функции передает управление следующему middleware в цепочке.
  • Завершение запроса: Если middleware отправляет ответ (res.send(), res.json(), res.render()) или передает ошибку в next(err), последующие обработчики для этого запроса не вызываются.
  • Обработка ошибок: Middleware с четырьмя аргументами (err, req, res, next) должен быть объявлен последним, после всех app.use() и маршрутов.