Что такое middleware в NestJS?

MiddleNestJS · Backend·Обновлено 3 июля 2026
Коротко
Middleware в NestJS — это функция, которая выполняется до обработчика маршрута и имеет доступ к объектам запроса (req), ответа (res) и функции next(). Используется для логирования, аутентификации, трансформации запросов и других сквозных задач.

Middleware в NestJS

Middleware — это промежуточный обработчик, встроенный в цепочку обработки HTTP-запроса между клиентом и конечным обработчиком маршрута. Концепция взята из Express.js, на котором NestJS основан по умолчанию.

Что умеет middleware

  • Выполнять произвольный код до обработки запроса
  • Изменять объекты req и res
  • Завершить цикл запрос-ответ досрочно
  • Вызвать следующий middleware через next()
  • Если next() не вызван — запрос «зависает»

Два способа создания

Класс-based middleware — рекомендованный подход в NestJS:

import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    // Логируем метод и URL входящего запроса
    console.log(`[${req.method}] ${req.url}`);
    next(); // Передаём управление дальше
  }
}

Функциональный middleware — простой вариант без DI:

import { Request, Response, NextFunction } from 'express';

export function loggerMiddleware(req: Request, res: Response, next: NextFunction) {
  console.log(`[${req.method}] ${req.url}`);
  next();
}

Подключение через AppModule

Middleware подключается в модуле через метод configure() с помощью MiddlewareConsumer:

import { Module, NestModule, MiddlewareConsumer, RequestMethod } from '@nestjs/common';
import { LoggerMiddleware } from './logger.middleware';
import { UsersModule } from './users/users.module';

@Module({
  imports: [UsersModule],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      // Применяем только к маршрутам /users с методом GET
      .forRoutes({ path: 'users', method: RequestMethod.GET });
  }
}

Гибкость настройки маршрутов

consumer
  .apply(AuthMiddleware, LoggerMiddleware) // Цепочка middleware
  .exclude(
    { path: 'auth/login', method: RequestMethod.POST }, // Исключаем публичный эндпоинт
  )
  .forRoutes('*'); // Применяем ко всем маршрутам

Middleware vs Guards vs Interceptors

Инструмент Порядок выполнения Типичное применение
Middleware 1-й Логирование, базовая трансформация req
Guard 2-й Аутентификация и авторизация
Interceptor 3-й (до/после) Трансформация ответа, кэширование
Pipe 4-й Валидация и трансформация данных

Важные особенности

Класс-based middleware поддерживает инъекцию зависимостей через @Injectable(), что позволяет использовать сервисы внутри middleware. Функциональный вариант этой возможности лишён.

Global middleware можно подключить через app.use() в main.ts, но такой middleware не имеет доступа к DI-контейнеру NestJS и является чисто Express-уровневым.

Что хочет услышать интервьюер

Понимание места middleware в жизненном цикле запроса NestJS (до Guards, Pipes, Interceptors)

Знание двух способов создания middleware: класс через NestMiddleware и функциональный

Умение подключить middleware через MiddlewareConsumer в модуле с настройкой маршрутов

Понимание разницы между middleware и Guards/Interceptors — когда что применять

Знание, что класс-based middleware поддерживает Dependency Injection, а функциональный — нет

Пример: Класс-based middleware с инъекцией зависимости

import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import { AuthService } from '../auth/auth.service';

@Injectable()
export class TokenMiddleware implements NestMiddleware {
  constructor(private readonly authService: AuthService) {}

  async use(req: Request, res: Response, next: NextFunction) {
    const token = req.headers['authorization']?.split(' ')[1];

    if (token) {
      // Декодируем токен и кладём пользователя в объект запроса
      req['user'] = await this.authService.decodeToken(token);
    }

    next();
  }
}

Пример: Подключение middleware в модуле

import { Module, NestModule, MiddlewareConsumer, RequestMethod } from '@nestjs/common';
import { TokenMiddleware } from './common/token.middleware';
import { UsersModule } from './users/users.module';
import { AuthModule } from './auth/auth.module';

@Module({
  imports: [UsersModule, AuthModule],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(TokenMiddleware)
      .exclude(
        // Логин и регистрация доступны без токена
        { path: 'auth/login', method: RequestMethod.POST },
        { path: 'auth/register', method: RequestMethod.POST },
      )
      .forRoutes('*'); // Применяем ко всем остальным маршрутам
  }
}

Типичные ошибки

Путают middleware с Guards — утверждают, что middleware — правильное место для авторизации, хотя Guards лучше подходят для этого

Забывают вызвать next() внутри middleware, из-за чего запрос зависает и не доходит до контроллера

Не знают, что global middleware через app.use() в main.ts не имеет доступа к DI-контейнеру

Не понимают порядок выполнения: думают, что Interceptors выполняются раньше Middleware

Не используют exclude() для исключения публичных маршрутов, пытаясь вместо этого добавлять условия внутри самого middleware

Лучшие курсы по теме

изображение курса

Docker и Ansible

Антон Ларичев
AI-тренажерыAI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Node.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Nest.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.6
3 999 ₽ 6 990 ₽
Подробнее