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

MiddleNestJS · Backend·Обновлено 27 июня 2026
Коротко
Interceptors — это классы с декоратором @Injectable(), реализующие интерфейс NestInterceptor, которые позволяют перехватывать выполнение метода контроллера до и после его вызова, трансформировать результат или обрабатывать исключения.

Interceptors в NestJS

Interceptor (перехватчик) — это механизм AOP (Aspect-Oriented Programming) в NestJS. Он оборачивает выполнение метода контроллера и позволяет выполнять дополнительную логику до и после его вызова, используя RxJS-поток.

Как устроен интерцептор

Каждый интерцептор реализует интерфейс NestInterceptor с единственным методом intercept. Этот метод получает два аргумента:

  • context: ExecutionContext — контекст выполнения, дающий доступ к объектам запроса и ответа
  • next: CallHandler — обработчик, вызов next.handle() которого запускает сам метод контроллера и возвращает Observable
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const now = Date.now();
    console.log('Запрос получен...');

    return next
      .handle()
      .pipe(
        // Код после выполнения метода контроллера
        tap(() => console.log(`Запрос выполнен за ${Date.now() - now}мс`)),
      );
  }
}

Основные сценарии использования

Трансформация ответа — оборачивание данных в единый формат:

import { map } from 'rxjs/operators';

@Injectable()
export class TransformInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next.handle().pipe(
      // Оборачиваем любой ответ в объект { data: ... }
      map((value) => ({ data: value })),
    );
  }
}

Кеширование — возврат кешированного значения без вызова контроллера:

import { of } from 'rxjs';

@Injectable()
export class CacheInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const cachedValue = this.cache.get(key);
    if (cachedValue) {
      // Возвращаем данные, не вызывая метод контроллера
      return of(cachedValue);
    }
    return next.handle();
  }
}

Привязка интерцептора

Интерцептор можно применить на трёх уровнях:

// На уровне метода
@Get()
@UseInterceptors(LoggingInterceptor)
findAll() {}

// На уровне контроллера
@UseInterceptors(LoggingInterceptor)
@Controller('users')
export class UsersController {}

// Глобально через модуль
// app.module.ts
{
  providers: [
    { provide: APP_INTERCEPTOR, useClass: LoggingInterceptor }
  ]
}

Отличие от других механизмов

Механизм Когда работает Доступ к response
Middleware До маршрутизации Да (Express)
Guard После middleware Нет
Interceptor До и после handler Через RxJS
Pipe Трансформация аргументов Нет
Filter Только при исключении Частично

Важная особенность: интерцепторы работают с RxJS Observable, что позволяет использовать всю мощь реактивных операторов: catchError, timeout, retry и другие.

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

Кандидат объясняет, что интерцептор реализует интерфейс NestInterceptor с методом intercept, принимающим ExecutionContext и CallHandler

Понимание разделения логики ДО вызова (код до next.handle()) и ПОСЛЕ вызова (операторы RxJS в pipe)

Знание типичных кейсов: логирование, трансформация ответа, кеширование, обработка ошибок

Понимание уровней применения: метод, контроллер, глобально через APP_INTERCEPTOR

Осознание отличий от Guards, Pipes и Middleware — в каком порядке они вызываются в lifecycle

Пример: Интерцептор логирования времени выполнения

import {
  Injectable,
  NestInterceptor,
  ExecutionContext,
  CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request = context.switchToHttp().getRequest();
    const { method, url } = request;
    const start = Date.now();

    console.log(`[${method}] ${url} — начало обработки`);

    return next.handle().pipe(
      tap(() => {
        console.log(`[${method}] ${url} — выполнено за ${Date.now() - start}мс`);
      }),
    );
  }
}

Пример: Трансформация ответа в единый формат

import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

export interface Response<T> {
  data: T;
  success: boolean;
}

@Injectable()
export class TransformInterceptor<T> implements NestInterceptor<T, Response<T>> {
  intercept(
    context: ExecutionContext,
    next: CallHandler,
  ): Observable<Response<T>> {
    return next.handle().pipe(
      // Все ответы оборачиваем в { data, success }
      map((data) => ({ data, success: true })),
    );
  }
}

Пример: Регистрация интерцептора глобально через APP_INTERCEPTOR

import { Module } from '@nestjs/common';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { TransformInterceptor } from './transform.interceptor';

@Module({
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useClass: TransformInterceptor,
    },
  ],
})
export class AppModule {}

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

Путают interceptors с middleware — middleware не имеет доступа к результату handler, интерцептор имеет

Забывают вызвать next.handle() — это приводит к тому, что метод контроллера не выполняется вообще

Не понимают, что next.handle() возвращает Observable, и пытаются работать с ним как с Promise

Применяют интерцептор через @UseInterceptors вместо APP_INTERCEPTOR, удивляясь что DI не работает корректно

Смешивают логику до и после выполнения в одном месте, не разделяя код до pipe() и код внутри pipe()

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

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

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 ₽
Подробнее