Какие знаешь этапы обработки запросов в NestJS?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Этапы обработки запросов в NestJS
NestJS построен на базе Express.js и предоставляет мощный механизм для обработки HTTP-запросов. Давайте разберём полный цикл жизни запроса от входа до отправки ответа.
Основная архитектура обработки
Порядок выполнения:
- Middleware → 2. Guards → 3. Interceptors (до контроллера) → 4. Pipes (валидация) → 5. Controller → 6. Service → 7. Interceptors (после контроллера) → 8. Exception Filters → 9. Response sent
Этап 1: Middleware
Middleware выполняется первым и имеет доступ к объектам Request и Response. Используется для общей обработки: логирования, парсинга body, аутентификации и т.п.
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) {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.path}`);
next();
}
}
// Регистрация в модуле
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(LoggerMiddleware).forRoutes("*");
}
}
Этап 2: Guards (Охранники)
Guards определяют, есть ли у пользователя доступ к конкретному маршруту. Используются для проверки аутентификации, авторизации и ролей.
import { Injectable, CanActivate, ExecutionContext } from "@nestjs/common";
@Injectable()
export class JwtGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
const token = request.headers.authorization?.split(" ")[1];
if (!token) return false;
try {
// Проверка и декодирование JWT
const decoded = jwt.verify(token, process.env.JWT_SECRET);
request.user = decoded;
return true;
} catch {
return false;
}
}
}
// Использование
@Controller("users")
export class UsersController {
@Get()
@UseGuards(JwtGuard)
findAll() {
return this.usersService.findAll();
}
}
Этап 3: Interceptors (Перехватчики)
Interceptors позволяют перехватить запрос до и после обработки. Используются для логирования, трансформации данных, обработки ошибок, кэширования.
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> {
console.log("Before...");
const now = Date.now();
return next.handle().pipe(
tap(() => {
console.log(`After... ${Date.now() - now}ms`);
})
);
}
}
// Применение на уровне контроллера или метода
@Controller("cats")
@UseInterceptors(LoggingInterceptor)
export class CatsController {
@Get()
findAll() {
return this.catsService.findAll();
}
}
Этап 4: Pipes (Трубы)
Pipes выполняют две основные функции: валидацию данных и трансформацию. Они обрабатывают параметры маршрута, query-параметры и body запроса.
import { PipeTransform, Injectable, BadRequestException } from "@nestjs/common";
@Injectable()
export class ParseIntPipe implements PipeTransform<string, number> {
transform(value: string): number {
const val = parseInt(value, 10);
if (isNaN(val)) {
throw new BadRequestException("Validation failed");
}
return val;
}
}
@Get(":id")
async getUser(
@Param("id", ParseIntPipe) id: number
) {
return this.usersService.findOne(id);
}
Встроенные Pipes:
ParseIntPipe— конвертация в числоParseBoolPipe— конвертация в booleanValidationPipe— валидация через класс-валидатор
Этап 5: Controller (Контроллер)
После всех проверок запрос поступает в метод контроллера. Контроллер обрабатывает параметры, вызывает сервисы и возвращает данные.
@Controller("users")
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
async findAll(@Query("limit") limit: number = 10) {
return this.usersService.findAll(limit);
}
@Post()
@UseInterceptors(ValidationPipe)
async create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}
}
Этап 6: Service (Сервис)
Сервис содержит бизнес-логику: работа с БД, вычисления, интеграции с внешними API и т.п.
@Injectable()
export class UsersService {
constructor(@InjectRepository(User) private usersRepository: Repository<User>) {}
async findAll(limit: number) {
return this.usersRepository.find({ take: limit });
}
async create(createUserDto: CreateUserDto) {
const user = this.usersRepository.create(createUserDto);
return this.usersRepository.save(user);
}
}
Этап 7: Interceptors (Постобработка)
После того, как контроллер вернул ответ, Interceptor может перехватить результат для трансформации или логирования.
Этап 8: Exception Filters (Фильтры исключений)
Если на любом из этапов произойдёт ошибка, она будет перехвачена Exception Filter и преобразована в HTTP-ответ.
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from "@nestjs/common";
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const status = exception.getStatus();
response.status(status).json({
statusCode: status,
message: exception.getResponse(),
timestamp: new Date().toISOString(),
});
}
}
// Применение
@UseFilters(HttpExceptionFilter)
@Controller("users")
export class UsersController {}
Полный пример обработки запроса
// Запрос: POST /users { "name": "John", "email": "john@example.com" }
// 1. Middleware проверяет аутентификацию и логирует
// 2. Guard проверяет, есть ли доступ
// 3. Interceptor логирует начало обработки
// 4. Pipe валидирует CreateUserDto через class-validator
// 5. Controller получает валидированные данные
// 6. Service сохраняет пользователя в БД
// 7. Interceptor преобразует ответ
// 8. Если ошибка — Exception Filter её перехватит
// 9. Ответ отправляется клиенту
Важные моменты
- Порядок имеет значение — Guards срабатывают раньше Pipes, это критично для безопасности
- Глобальные vs локальные — можно применять на уровне модуля, контроллера или метода
- Асинхронные операции — все эти компоненты могут быть асинхронными
- Тестирование — каждый компонент можно тестировать отдельно благодаря модульной архитектуре
Понимание этапов обработки запроса критично для написания чистого и безопасного кода в NestJS.