← Назад к вопросам

Что такое middleware в Express.js и как он работает?

1.3 Junior🔥 181 комментариев
#Node.js и JavaScript#Фреймворки и библиотеки

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Middleware в Express.js: полное руководство

Middleware — это функция, которая имеет доступ к объектам request (req), response (res) и следующему middleware в цепочке обработки запроса. Это один из самых важных концептов Express.js.

Основное определение

Middleware — это функция с сигнатурой:

(req, res, next) => { ... }
  • req — объект HTTP запроса
  • res — объект HTTP ответа
  • next — функция для передачи управления следующему middleware

Как работает middleware?

Middleware работают в виде конвейера (pipeline). Каждый middleware может:

  1. Обработать запрос
  2. Модифицировать req или res
  3. Отправить ответ (завершить конвейер)
  4. Передать управление следующему middleware через next()
Request
  ↓
┌─────────────────┐
│ Middleware 1    │
│ (Authentication)│ ← Проверка токена
└─────────────────┘
  ↓ next()
┌─────────────────┐
│ Middleware 2    │
│ (Logging)       │ ← Логирование
└─────────────────┘
  ↓ next()
┌─────────────────┐
│ Middleware 3    │
│ (Validation)    │ ← Валидация
└─────────────────┘
  ↓ next()
┌─────────────────┐
│ Route Handler   │
│ (Controller)    │ ← Основная логика
└─────────────────┘
  ↓ res.send()
Response

Пример 1: Простой middleware

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

// Middleware функция
const loggingMiddleware = (req, res, next) => {
  console.log(`${req.method} ${req.path}`);
  next(); // Передаём управление дальше
};

// Регистрируем middleware ДЛЯ ВСЕХ маршрутов
app.use(loggingMiddleware);

// Route handler
app.get('/users', (req, res) => {
  res.json({ users: [] });
});

app.listen(3000);

// При запросе GET /users:
// 1. Вызывается loggingMiddleware → выводит "GET /users"
// 2. Вызывается next() → переходит к обработчику маршрута
// 3. Отправляется ответ { users: [] }

Пример 2: Middleware с модификацией запроса

// Middleware для добавления информации о пользователе
const authMiddleware = (req, res, next) => {
  // Проверяем токен
  const token = req.headers.authorization?.split(' ')[1];
  
  if (!token) {
    return res.status(401).json({ error: 'No token' });
  }
  
  // Парсим токен (без проверки подписи для примера)
  try {
    const decoded = { userId: 123, username: 'john' }; // В реальности парсим JWT
    req.user = decoded; // Добавляем в объект req
    next();
  } catch (err) {
    res.status(401).json({ error: 'Invalid token' });
  }
};

app.use(authMiddleware);

app.get('/profile', (req, res) => {
  // req.user доступен благодаря middleware
  res.json({ user: req.user });
});

Пример 3: Middleware для отдельных маршрутов

// Применяем middleware только к конкретному маршруту
const adminOnlyMiddleware = (req, res, next) => {
  if (req.user?.role !== 'admin') {
    return res.status(403).json({ error: 'Forbidden' });
  }
  next();
};

// Без middleware
app.get('/public', (req, res) => {
  res.json({ message: 'Public page' });
});

// С middleware
app.get('/admin', adminOnlyMiddleware, (req, res) => {
  res.json({ message: 'Admin page' });
});

// С несколькими middleware
app.post(
  '/admin/users',
  authMiddleware,    // Проверка аутентификации
  adminOnlyMiddleware, // Проверка прав
  (req, res) => {     // Основной обработчик
    res.json({ message: 'Create user' });
  }
);

Типы middleware

1. Application-level middleware (для всех маршрутов)

app.use((req, res, next) => {
  console.log('Request received');
  next();
});

2. Router-level middleware (для маршрутов роутера)

const router = express.Router();

router.use((req, res, next) => {
  console.log('Router middleware');
  next();
});

router.get('/users', (req, res) => {
  res.json({ users: [] });
});

app.use('/api', router);

3. Error-handling middleware (4 параметра!)

// ОБЯЗАТЕЛЬНО 4 параметра для ошибок!
app.use((err, req, res, next) => {
  console.error('Error:', err.message);
  res.status(500).json({ error: err.message });
});

4. Built-in middleware

// Express встроенные middleware
app.use(express.json());        // Парсинг JSON тела
app.use(express.urlencoded()); // Парсинг форм
app.use(express.static('public')); // Статические файлы

5. Third-party middleware

const cors = require('cors');
const helmet = require('helmet');

app.use(cors());           // CORS
app.use(helmet());         // Безопасность
app.use(morgan('combined')); // Логирование

Пример 4: Цепочка middleware

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

// Middleware 1: логирование
const logger = (req, res, next) => {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.path}`);
  next();
};

// Middleware 2: парсинг JSON
const jsonParser = express.json();

// Middleware 3: валидация
const validateUser = (req, res, next) => {
  if (!req.body.name || !req.body.email) {
    return res.status(400).json({ error: 'Missing fields' });
  }
  next();
};

// Регистрируем middleware по порядку
app.use(logger);      // Вызывается первым
app.use(jsonParser);  // Вызывается вторым

app.post('/users', validateUser, (req, res) => {
  // Вызывается третьим (validateUser)
  // Затем обработчик маршрута
  res.status(201).json({ id: 1, ...req.body });
});

app.listen(3000);

Пример 5: Middleware с асинхронностью

// ✓ Правильно: используем async/await
const fetchUserMiddleware = async (req, res, next) => {
  try {
    const user = await database.users.findById(req.params.userId);
    if (!user) {
      return res.status(404).json({ error: 'User not found' });
    }
    req.user = user;
    next();
  } catch (err) {
    next(err); // Передаём ошибку в error-handling middleware
  }
};

app.get('/users/:userId', fetchUserMiddleware, (req, res) => {
  res.json(req.user);
});

// ✓ Error handling
app.use((err, req, res, next) => {
  console.error(err);
  res.status(500).json({ error: 'Internal server error' });
});

Пример 6: Реальное приложение

const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const morgan = require('morgan');
const jwt = require('jsonwebtoken');

const app = express();

// Security middleware
app.use(helmet());
app.use(cors());

// Logging middleware
app.use(morgan('combined'));

// Body parsing middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// Authentication middleware
const authMiddleware = (req, res, next) => {
  const token = req.headers.authorization?.split(' ')[1];
  if (!token) return res.status(401).json({ error: 'No token' });
  
  try {
    req.user = jwt.verify(token, 'secret');
    next();
  } catch (err) {
    res.status(401).json({ error: 'Invalid token' });
  }
};

// Public route (БЕЗ middleware)
app.post('/auth/login', (req, res) => {
  const token = jwt.sign({ id: 1, username: 'john' }, 'secret');
  res.json({ token });
});

// Protected route (С middleware)
app.get('/users', authMiddleware, (req, res) => {
  res.json({ user: req.user });
});

// Error handling middleware (ПОСЛЕДНИЙ!)
app.use((err, req, res, next) => {
  console.error(err);
  res.status(500).json({ error: 'Internal server error' });
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

Важные правила

  1. Порядок имеет значение — middleware выполняются в том порядке, в котором зарегистрированы
  2. ОБЯЗАТЕЛЬНО вызывай next() (если не отправляешь ответ)
  3. Ошибки в middleware → передавай в следующий middleware через next(err)
  4. Error-handling middleware с 4 параметрами должен быть ПОСЛЕДНИМ
  5. Не вызывай next() дважды — это вызовет ошибку
  6. Для асинхронности используй async/await и обрабатывай ошибки

Распространённые ошибки

// ✗ ОШИБКА: забыли вызвать next()
app.use((req, res) => {
  console.log('Request');
  // Запрос зависнет!
});

// ✓ ПРАВИЛЬНО
app.use((req, res, next) => {
  console.log('Request');
  next(); // Передаём управление
});

// ✗ ОШИБКА: вызвали next() дважды
app.get('/users', (req, res, next) => {
  res.send('Users');
  next(); // Ошибка!
});

// ✓ ПРАВИЛЬНО: отправляем ответ ИЛИ вызываем next(), не оба
app.get('/users', (req, res, next) => {
  res.send('Users');
  // Не вызываем next()
});

Заключение

Middleware — это фундаментальный концепт Express.js, который позволяет обрабатывать запрос на разных этапах. Они используются для аутентификации, валидации, логирования, обработки ошибок и многого другого. Ключ к правильной работе — понимание порядка выполнения и обязательный вызов next() для передачи управления следующему middleware.