Что такое порядок middleware в Express.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() и маршрутов.

Ответ 18+ 🔞

А, слушай, вот эта тема с middleware в Express — это вообще отдельная песня, блядь. Представь себе конвейер на заводе, только вместо деталей у тебя запросы, а вместо станков — эти самые функции-обработчики. И вся соль в том, что они идут строго по очереди, как ты их в коде расставил. Один за другим, без фокусов. Если поставишь не туда — получишь пиздец, а не приложение.

Вот смотри, самый простой пример, чтобы мозги не расплавились сразу:

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

// 1. Вот этот парень будет первым, типа охранник на проходной, который всех записывает.
app.use((req, res, next) => {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
  next(); // Это как сказать: "Ладно, проходи дальше, следующий!"
});

// 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. А ЭТОГО товарища ставят ВСЕГДА В САМЫЙ КОНЕЦ. Он как санитар, который подбирает тех, кого все остальные уронили.
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

Теперь главные правила, без которых нихуя не получится, ёпта:

  • next() — это святое. Не вызовешь — запрос так и зависнет в этом обработчике, как дурак, и будет ждать до скончания времён. Это как передать эстафетную палочку.
  • Если отправил ответ — всё, приехали. Как только кто-то сделал res.send() или res.json(), все остальные middleware могут идти лесом, цепочка обрывается. Исключение — если специально ошибку в next(err) кинуть.
  • Обработчик ошибок — это как пожарный. Его ставят в самом конце, после всех маршрутов и обычных middleware. Он ловит только те ошибки, которые до него долетели. Если поставить его в начало — он нихуя не поймает, потому что ошибка случится позже, а он уже проехал.

Короче, вся логика — это чёткая очередь. Сначала логируем, потом парсим, потом проверяем права, потом работаем, и только в самом конце, если что-то пошло не так, прибегает уборщик-ликвидатор. Запомни эту последовательность, и волнение ебать тебя покинет.