{T}

NestJS核心概念与请求生命周期

一、NestJS 核心概念

1.1 后端代码组织问题

传统问题

code
后端开发面临的问题:
│
├──  如何组织代码?
│   ├── 路由处理分文件
│   ├── 业务逻辑分文件
│   └── 数据库操作分文件
│
├──  NestJS 的解决方案
│   ├── 提供清晰的核心概念
│   ├── 约定优于配置
│   └── 模块化架构设计
│
└──  核心思想
    └── 让代码逻辑分层更合理,更易理解和维护

1.2 三大核心概念

NestJS 架构图

code
┌─────────────────────────────────────────────────────────┐
│                      客户端(Client)                    │
│                   发送 HTTP 请求                         │
└─────────────────────┬───────────────────────────────────┘
                      │
                      ▼
┌─────────────────────────────────────────────────────────┐
│              控制器层(Controller Layer)                │
│  ┌───────────────────────────────────────────────────┐  │
│  │  • 接收请求                                         │  │
│  │  • 解析请求方法(GET/POST/PUT/DELETE)              │  │
│  │  • 分发到对应服务                                   │  │
│  │  • 返回响应                                         │  │
│  └───────────────────────────────────────────────────┘  │
└─────────────────────┬───────────────────────────────────┘
                      │ 调用
                      ▼
┌─────────────────────────────────────────────────────────┐
│               服务层(Service Layer)                    │
│  ┌───────────────────────────────────────────────────┐  │
│  │  • 业务逻辑处理                                     │  │
│  │  • 数据处理和转换                                   │  │
│  │  • 调用数据访问层                                   │  │
│  │  • 返回处理结果                                     │  │
│  └───────────────────────────────────────────────────┘  │
└─────────────────────┬───────────────────────────────────┘
                      │ 查询
                      ▼
┌─────────────────────────────────────────────────────────┐
│         数据访问层(Data Access Layer)                  │
│  ┌───────────────────────────────────────────────────┐  │
│  │  • 数据库模型定义                                   │  │
│  │  • 数据库查询操作                                   │  │
│  │  • 数据持久化                                       │  │
│  │  • ORM/ODM 操作                                     │  │
│  └───────────────────────────────────────────────────┘  │
└─────────────────────┬───────────────────────────────────┘
                      │
                      ▼
                ┌──────────┐
                │ 数据库    │
                │ Database │
                └──────────┘

1.3 各层职责详解

Controller(控制器层)

职责

职责说明
处理请求接收客户端 HTTP 请求
路由分发解析请求方法(GET/POST/PUT/DELETE)和路径
参数提取从请求中提取参数、请求体、查询参数等
调用服务将请求转发给对应的 Service 处理
返回响应将处理结果返回给客户端

代码示例

typescript
// src/users/users.controller.ts
import { Controller, Get, Post, Body, Param, Query } from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';

@Controller('users')
export class UsersController {
  //  依赖注入:通过构造函数注入 Service
  constructor(private readonly usersService: UsersService) {}

  // GET /users
  @Get()
  findAll() {
    // 调用 Service 处理业务逻辑
    return this.usersService.findAll();
  }

  // GET /users/:id
  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.usersService.findOne(+id);
  }

  // POST /users
  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    return this.usersService.create(createUserDto);
  }

  // PUT /users/:id
  @Put(':id')
  update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
    return this.usersService.update(+id, updateUserDto);
  }

  // DELETE /users/:id
  @Delete(':id')
  remove(@Param('id') id: string) {
    return this.usersService.remove(+id);
  }
}

Service(服务层)

职责

职责说明
业务逻辑处理核心业务逻辑
数据处理数据转换、计算、验证
复用性多个 Controller 可复用同一 Service
数据访问调用 Repository 或数据库进行数据操作

为什么需要 Service?

code
Service 层的价值:
│
├──  复用性
│   ├── 接口 A 需要查询用户信息
│   ├── 接口 B 也需要查询用户信息
│   └── 提取成 Service,避免代码重复
│
├──  单一职责
│   ├── Controller 只负责路由分发
│   ├── Service 负责业务逻辑
│   └── 职责清晰,易于维护
│
└──  可测试性
    ├── Service 可独立测试
    ├── Controller 可模拟 Service
    └── 便于单元测试和集成测试

代码示例

typescript
// src/users/users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './entities/user.entity';
import { CreateUserDto } from './dto/create-user.dto';

@Injectable() //  标记为可注入的 Provider
export class UsersService {
  constructor(
    @InjectRepository(User)
    private userRepository: Repository<User>,
  ) {}

  // 查询所有用户
  async findAll(): Promise<User[]> {
    return this.userRepository.find();
  }

  // 查询单个用户
  async findOne(id: number): Promise<User> {
    return this.userRepository.findOne({ where: { id } });
  }

  // 创建用户
  async create(createUserDto: CreateUserDto): Promise<User> {
    const user = this.userRepository.create(createUserDto);
    return this.userRepository.save(user);
  }

  // 更新用户
  async update(id: number, updateUserDto: UpdateUserDto): Promise<User> {
    await this.userRepository.update(id, updateUserDto);
    return this.findOne(id);
  }

  // 删除用户
  async remove(id: number): Promise<void> {
    await this.userRepository.delete(id);
  }
}

Data Access Layer(数据访问层)重要

职责

职责说明
模型定义定义数据库实体(Entity/Model)
数据查询封装数据库查询操作
数据持久化负责数据的 CRUD 操作
ORM 集成集成 TypeORM、Prisma、Mongoose 等

代码示例

typescript
// src/users/entities/user.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity('users') // 对应数据库表名
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ length: 100 })
  name: string;

  @Column({ unique: true })
  email: string;

  @Column()
  age: number;

  @Column({ default: true })
  isActive: boolean;

  @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
  createdAt: Date;

  @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP', onUpdate: 'CURRENT_TIMESTAMP' })
  updatedAt: Date;
}

// src/users/users.repository.ts(可选)
import { EntityRepository, Repository } from 'typeorm';
import { User } from './entities/user.entity';

@EntityRepository(User)
export class UsersRepository extends Repository<User> {
  // 自定义查询方法
  async findActiveUsers(): Promise<User[]> {
    return this.createQueryBuilder('user')
      .where('user.isActive = :isActive', { isActive: true })
      .getMany();
  }

  async findByEmail(email: string): Promise<User | undefined> {
    return this.findOne({ where: { email } });
  }
}

1.4 各层之间的关系

依赖关系图

code
依赖关系:

┌──────────────┐
│   Client     │ 发送请求
└──────┬───────┘
       │
       ▼
┌──────────────┐ 依赖
│  Controller  │──────┐
└──────────────┘      │
                      │
                      ▼
                ┌──────────────┐ 依赖
                │   Service    │──────┐
                └──────────────┘      │
                                      │
                                      ▼
                                ┌──────────────┐
                                │  Repository  │
                                └──────┬───────┘
                                       │
                                       ▼
                                 ┌──────────┐
                                 │ Database │
                                 └──────────┘

设计模式:
• 控制器 → 服务:依赖注入(DI)
• 服务 → 仓库:依赖注入(DI)
• 整体架构:面向切面编程(AOP)

二、NestJS 请求生命周期

2.1 生命周期概览

完整生命周期流程

code
NestJS 请求生命周期(非常重要):

客户端(Client)
    │
    │ 发送请求
    ▼
┌─────────────────────────────────────────────────────────┐
│ 1⃣ 中间件(Middleware)                                  │
│    └─ 全局中间件 → 模块中间件                             │
└─────────────────────┬───────────────────────────────────┘
                      ▼
┌─────────────────────────────────────────────────────────┐
│ 2⃣ 守卫(Guard)                                         │
│    └─ 全局守卫 → 控制器守卫 → 路由守卫                    │
└─────────────────────┬───────────────────────────────────┘
                      ▼
┌─────────────────────────────────────────────────────────┐
│ 3⃣ 拦截器 - 前置(Interceptor Before)                   │
│    └─ 全局拦截器 → 控制器拦截器 → 路由拦截器              │
└─────────────────────┬───────────────────────────────────┘
                      ▼
┌─────────────────────────────────────────────────────────┐
│ 4⃣ 管道(Pipe)                                          │
│    └─ 全局管道 → 控制器管道 → 路由管道 → 参数管道         │
└─────────────────────┬───────────────────────────────────┘
                      ▼
┌─────────────────────────────────────────────────────────┐
│ 5⃣ 控制器方法(Controller Method)                       │
│    └─ 处理请求、调用服务                                  │
└─────────────────────┬───────────────────────────────────┘
                      ▼
┌─────────────────────────────────────────────────────────┐
│ 6⃣ 服务(Service)                                       │
│    └─ 业务逻辑处理、数据库操作                            │
└─────────────────────┬───────────────────────────────────┘
                      ▼
┌─────────────────────────────────────────────────────────┐
│ 7⃣ 拦截器 - 后置(Interceptor After)                    │
│    └─ 路由拦截器 → 控制器拦截器 → 全局拦截器              │
│     注意:与前置拦截器顺序相反                          │
└─────────────────────┬───────────────────────────────────┘
                      ▼
┌─────────────────────────────────────────────────────────┐
│ 8⃣ 异常过滤器(Exception Filter)                        │
│    └─ 路由过滤器 → 控制器过滤器 → 全局过滤器              │
│     仅在异常发生时执行                                  │
└─────────────────────┬───────────────────────────────────┘
                      ▼
                  响应(Response)
                      │
                      ▼
                  客户端(Client)

2.2 洋葱模型理解

洋葱模型示意图

code
                    洋葱模型(类似 Koa/Express)

                         ┌─────────────┐
                         │   Client    │
                         └──────┬──────┘
                                │
               ┌────────────────┼────────────────┐
               │                ▼                │
               │         ┌─────────────┐         │
               │         │ Middleware  │         │
               │         └──────┬──────┘         │
               │                │                │
        ┌──────┴──────┐         ▼         ┌──────┴──────┐
        │             │  ┌─────────────┐  │             │
        │             │  │    Guard    │  │             │
        │             │  └──────┬──────┘  │             │
        │             │         │         │             │
   ┌────┴────┐        │         ▼         │        ┌────┴────┐
   │         │        │  ┌─────────────┐  │        │         │
   │         │        │  │ Interceptor │  │        │         │
   │         │        │  │   (Before)  │  │        │         │
   │         │        │  └──────┬──────┘  │        │         │
   │         │        │         │         │        │         │
   │         │   ┌────┴────┐    ▼    ┌────┴────┐   │         │
   │         │   │         │ ┌─────┐ │         │   │         │
   │         │   │         │ │Pipe │ │         │   │         │
   │         │   │         │ └──┬──┘ │         │   │         │
   │         │   │         │    │    │         │   │         │
   │         │   │         │    ▼    │         │   │         │
   │         │   │         │ ┌─────┐ │         │   │         │
   │         │   │         │ │  ↓  │ │         │   │         │
   │         │   │         │ │ Ctrl│ │         │   │         │
   │         │   │         │ │ Svc │ │         │   │         │
   │         │   │         │ │  ↑  │ │         │   │         │
   │         │   │         │ └─────┘ │         │   │         │
   │         │   │         │    │    │         │   │         │
   │         │   │         │    ▼    │         │   │         │
   │         │   │         │ ┌─────┐ │         │   │         │
   │         │   │         │ │Inter│ │         │   │         │
   │         │   │         │ │(Aft)│ │         │   │         │
   │         │   └────┬────┘ └─────┘ └────┬────┘   │         │
   │         │        │         ▲         │        │         │
   │         │        │  ┌─────────────┐  │        │         │
   │         │        │  │   Filter   │  │        │         │
   │         │        │  └─────────────┘  │        │         │
   │         │        │                   │        │         │
   └─────────┴────────┴───────────────────┴────────┴─────────┘
                                │
                                ▼
                          ┌──────────┐
                          │ Response │
                          └──────────┘

关键点:
• 请求从外向内穿透(前置处理)
• 响应从内向外穿透(后置处理)
• 前置和后置拦截器顺序相反

2.3 各环节详解

1. 中间件(Middleware)

执行时机:请求最先到达

执行顺序:全局中间件 → 模块中间件

职责

code
中间件职责:
│
├──  日志记录
│   └── 记录请求信息、响应时间
│
├──  安全处理
│   └── CORS、CSRF、Helmet 等
│
├──  请求预处理
│   └── 解析请求体、添加请求头
│
└──  性能监控
    └── 统计请求处理时间

代码示例

typescript
// src/common/middleware/logger.middleware.ts
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.url}`);
    
    const start = Date.now();
    
    res.on('finish', () => {
      const duration = Date.now() - start;
      console.log(`请求处理时间: ${duration}ms`);
    });
    
    next();
  }
}

// 在模块中配置
// src/app.module.ts
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';

@Module({})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes('*'); // 应用到所有路由
  }
}

2. 守卫(Guard)

执行时机:中间件之后

执行顺序:全局守卫 → 控制器守卫 → 路由守卫

职责

code
守卫职责:
│
├──  身份认证
│   └── 验证 Token、Session
│
├──  权限验证
│   └── 检查用户角色、权限
│
├──  访问控制
│   └── 允许或拒绝请求
│
└──  返回布尔值
    ├── true:继续执行
    └── false:抛出 403 异常

代码示例

typescript
// src/common/guards/auth.guard.ts
import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common';

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest();
    const token = request.headers.authorization;

    if (!token) {
      throw new UnauthorizedException('未提供认证令牌');
    }

    // 验证 Token
    const isValid = this.validateToken(token);
    
    if (!isValid) {
      throw new UnauthorizedException('无效的认证令牌');
    }

    return true; // 允许继续执行
  }

  private validateToken(token: string): boolean {
    // 实际项目中应该使用 JWT 验证
    return token === 'valid-token';
  }
}

// 使用示例
@Controller('users')
@UseGuards(AuthGuard) // 控制器级别
export class UsersController {
  
  @Get('admin')
  @UseGuards(AdminGuard) // 路由级别
  getAdminData() {
    return { message: '管理员数据' };
  }
}

3. 拦截器 - 前置(Interceptor Before)

执行时机:守卫之后

执行顺序:全局拦截器 → 控制器拦截器 → 路由拦截器

职责

code
前置拦截器职责:
│
├──  请求日志
│   └── 记录请求参数、时间戳
│
├──  请求转换
│   └── 修改请求数据
│
├── ⏱ 性能监控
│   └── 记录开始时间
│
└──  缓存检查
    └── 检查缓存是否存在

代码示例

typescript
// src/common/interceptors/logging.interceptor.ts
import { Injectable, NestInterceptor, ExecutionContext, CallHandler, Logger } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  private readonly logger = new Logger(LoggingInterceptor.name);

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request = context.switchToHttp().getRequest();
    const { method, url, body } = request;
    const now = Date.now();

    // 前置处理:记录请求信息
    this.logger.log(`\n
      ========== 请求开始 ==========
      方法: ${method}
      路径: ${url}
      请求体: ${JSON.stringify(body)}
      时间: ${new Date().toISOString()}
      ==============================
    `);

    return next.handle().pipe(
      tap((data) => {
        // 后置处理:记录响应信息
        const duration = Date.now() - now;
        this.logger.log(`\n
          ========== 响应完成 ==========
          路径: ${url}
          耗时: ${duration}ms
          ==============================
        `);
      }),
    );
  }
}

4. 管道(Pipe)

执行时机:拦截器之后

执行顺序:全局管道 → 控制器管道 → 路由管道 → 参数管道

职责

code
管道职责:
│
├──  参数验证
│   └── 验证请求参数格式、类型
│
├──  数据转换
│   └── 字符串转数字、日期转换
│
├──  数据清洗
│   └── 去除空格、过滤字段
│
└──  验证失败
    └── 抛出 400 Bad Request

代码示例

typescript
// src/common/pipes/validation.pipe.ts
import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
import { validate } from 'class-validator';
import { plainToInstance } from 'class-transformer';

@Injectable()
export class ValidationPipe implements PipeTransform<any> {
  async transform(value: any, { metatype }: ArgumentMetadata) {
    if (!metatype || !this.toValidate(metatype)) {
      return value;
    }

    const object = plainToInstance(metatype, value);
    const errors = await validate(object);

    if (errors.length > 0) {
      const messages = errors.map(error => ({
        property: error.property,
        constraints: error.constraints,
      }));

      throw new BadRequestException({
        code: 400,
        message: '参数验证失败',
        errors: messages,
      });
    }

    return value;
  }

  private toValidate(metatype: Function): boolean {
    const types: Function[] = [String, Boolean, Number, Array, Object];
    return !types.includes(metatype);
  }
}

// 使用示例
@Post()
create(@Body() createUserDto: CreateUserDto) {
  // 参数已自动验证
  return this.usersService.create(createUserDto);
}

5. 控制器方法(Controller Method)

执行时机:管道之后

职责

code
控制器方法职责:
│
├──  接收验证后的参数
│
├──  调用服务方法
│
├──  返回处理结果
│
└──  路由分发

代码示例

typescript
@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    // 参数已通过管道验证
    // 调用 Service 处理业务逻辑
    return this.usersService.create(createUserDto);
  }
}

6. 服务(Service)

执行时机:控制器调用后

职责

code
服务职责:
│
├──  业务逻辑处理
│
├──  数据计算和转换
│
├──  数据库操作
│
├──  调用其他服务
│
└──  返回处理结果

代码示例

typescript
@Injectable()
export class UsersService {
  async create(createUserDto: CreateUserDto): Promise<User> {
    // 1. 业务逻辑处理
    const hashedPassword = await this.hashPassword(createUserDto.password);
    
    // 2. 数据库操作
    const user = this.userRepository.create({
      ...createUserDto,
      password: hashedPassword,
    });
    
    // 3. 保存数据
    await this.userRepository.save(user);
    
    // 4. 返回结果
    return user;
  }
}

7. 拦截器 - 后置(Interceptor After)

执行时机:服务返回后

执行顺序:路由拦截器 → 控制器拦截器 → 全局拦截器(与前置相反)

职责

code
后置拦截器职责:
│
├──  响应日志
│   └── 记录响应数据
│
├──  响应转换
│   └── 统一响应格式
│
├──  缓存保存
│   └── 将结果缓存
│
└── ⏱ 性能统计
    └── 计算总耗时

响应转换示例

typescript
// src/common/interceptors/transform.interceptor.ts
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

export interface Response<T> {
  code: number;
  data: T;
  message: string;
  timestamp: string;
}

@Injectable()
export class TransformInterceptor<T> implements NestInterceptor<T, Response<T>> {
  intercept(context: ExecutionContext, next: CallHandler): Observable<Response<T>> {
    return next.handle().pipe(
      map(data => ({
        code: 0,
        data,
        message: '请求成功',
        timestamp: new Date().toISOString(),
      })),
    );
  }
}

// 响应格式
{
  "code": 0,
  "data": { "id": 1, "name": "张三" },
  "message": "请求成功",
  "timestamp": "2026-03-07T10:30:00.000Z"
}

8. 异常过滤器(Exception Filter)

执行时机:仅当异常发生时

执行顺序:路由过滤器 → 控制器过滤器 → 全局过滤器

职责

code
异常过滤器职责:
│
├──  捕获异常
│   └── 捕获未处理的异常
│
├──  记录错误日志
│   └── 记录异常堆栈信息
│
├──  格式化错误响应
│   └── 统一错误返回格式
│
└──  错误监控
    └── 发送错误通知

代码示例

typescript
// src/common/filters/http-exception.filter.ts
import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpException,
  HttpStatus,
  Logger,
} from '@nestjs/common';
import { Request, Response } from 'express';

@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
  private readonly logger = new Logger(HttpExceptionFilter.name);

  catch(exception: unknown, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();

    let status = HttpStatus.INTERNAL_SERVER_ERROR;
    let message = '服务器内部错误';
    let error = 'Internal Server Error';

    if (exception instanceof HttpException) {
      status = exception.getStatus();
      const exceptionResponse = exception.getResponse();
      
      if (typeof exceptionResponse === 'object') {
        message = (exceptionResponse as any).message || message;
        error = (exceptionResponse as any).error || error;
      }
    }

    // 记录错误日志
    this.logger.error(`\n
      ========== 异常信息 ==========
      路径: ${request.url}
      方法: ${request.method}
      状态码: ${status}
      错误: ${error}
      消息: ${message}
      ==============================
    `);

    // 统一返回格式
    response.status(status).json({
      code: status,
      data: null,
      message: message,
      error: error,
      timestamp: new Date().toISOString(),
      path: request.url,
    });
  }
}

2.4 生命周期完整示例

完整请求流程代码

typescript
// ========== 1. 中间件 ==========

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    console.log('1⃣ 中间件:记录请求日志');
    next();
  }
}

// ========== 2. 守卫 ==========

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    console.log('2⃣ 守卫:验证用户身份');
    return true;
  }
}

// ========== 3. 拦截器(前置)==========

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    console.log('3⃣ 拦截器(前置):请求开始');
    
    return next.handle().pipe(
      tap(() => {
        console.log('7⃣ 拦截器(后置):响应完成');
      }),
    );
  }
}

// ========== 4. 管道 ==========

@Injectable()
export class ValidationPipe implements PipeTransform {
  transform(value: any, metadata: ArgumentMetadata) {
    console.log('4⃣ 管道:参数验证');
    return value;
  }
}

// ========== 5. 控制器 ==========

@Controller('users')
@UseGuards(AuthGuard)
@UseInterceptors(LoggingInterceptor)
@UsePipes(ValidationPipe)
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    console.log('5⃣ 控制器:处理请求');
    return this.usersService.create(createUserDto);
  }
}

// ========== 6. 服务 ==========

@Injectable()
export class UsersService {
  async create(createUserDto: CreateUserDto) {
    console.log('6⃣ 服务:业务逻辑处理');
    return { id: 1, ...createUserDto };
  }
}

// ========== 8. 异常过滤器 ==========

@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: unknown, host: ArgumentsHost) {
    console.log('8⃣ 异常过滤器:捕获异常');
    // 处理异常
  }
}

// ========== 执行顺序 ==========

// 控制台输出:
// 1⃣ 中间件:记录请求日志
// 2⃣ 守卫:验证用户身份
// 3⃣ 拦截器(前置):请求开始
// 4⃣ 管道:参数验证
// 5⃣ 控制器:处理请求
// 6⃣ 服务:业务逻辑处理
// 7⃣ 拦截器(后置):响应完成

三、前端框架生命周期对比

3.1 对比表

框架生命周期钩子说明
Vuemounted组件挂载后执行
ReactcomponentDidMount组件挂载后执行
NestJS中间件、守卫、拦截器等请求处理各阶段

3.2 理解方式

code
前端 vs 后端生命周期理解:

前端生命周期:
│
├── 创建阶段
│   └── beforeCreate、created
│
├── 挂载阶段
│   └── beforeMount、mounted
│
├── 更新阶段
│   └── beforeUpdate、updated
│
└── 销毁阶段
    └── beforeDestroy、destroyed

后端生命周期:
│
├── 请求阶段(前置)
│   └── 中间件 → 守卫 → 拦截器 → 管道
│
├── 处理阶段
│   └── 控制器 → 服务
│
└── 响应阶段(后置)
    └── 拦截器 → 过滤器 → 响应

共同点:
• 都是钩子方法
• 都在特定时机执行
• 都可以插入自定义逻辑

四、生命周期记忆技巧

4.1 简化理解

code
生命周期简化记忆:

请求流程:客户端 → 中间件 → 守卫 → 拦截器 → 管道 → 控制器 → 服务

响应流程:服务 → 拦截器(反向)→ 过滤器 → 客户端

关键点:
1⃣ 中间件最先执行
2⃣ 守卫验证权限
3⃣ 拦截器前后都有(洋葱模型)
4⃣ 管道验证参数
5⃣ 控制器处理请求
6⃣ 服务处理业务
7⃣ 过滤器处理异常

4.2 不需要死记硬背

code
学习建议:
│
├──  理解每个组件的作用
│   └── 中间件干啥?守卫干啥?
│
├──  知道大致顺序
│   └── 前置 → 处理 → 后置
│
├──  需要时查阅文档
│   └── 这张图不需要背
│
└──  用过一次就记住了
    └── 实践是最好的老师

五、最佳实践

5.1 各组件使用场景

组件使用场景示例
Middleware日志、安全、CORS请求日志、Helmet
Guard认证、授权JWT 验证、角色检查
Interceptor日志、转换、缓存响应格式化、缓存
Pipe验证、转换DTO 验证、类型转换
Filter异常处理统一错误响应

5.2 性能优化建议

typescript
//  避免:在守卫中执行耗时操作
@Injectable()
export class BadGuard implements CanActivate {
  async canActivate(context: ExecutionContext): boolean {
    // 不要在守卫中执行数据库查询
    await this.userService.findAll(); // 性能杀手
    return true;
  }
}

//  推荐:守卫只做轻量级验证
@Injectable()
export class GoodGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest();
    const token = request.headers.authorization;
    return !!token; // 简单验证
  }
}

六、常见问题与解决方案

问题原因解决方案
守卫不执行未正确注册使用 @UseGuards() 或全局注册
拦截器执行两次前置和后置都执行这是正常行为,洋葱模型
管道验证无效未启用 ValidationPipe在 main.ts 中启用
过滤器不捕获异常异常类型不匹配使用 @Catch() 指定异常类型
执行顺序错误不了解生命周期参考本文档的生命周期图
性能问题组件中执行耗时操作保持组件轻量,避免数据库查询

七、学习要点总结

核心要点

  1. 三大核心概念:Controller(控制器)、Service(服务)、Data Access(数据访问层)
  2. 请求生命周期:中间件 → 守卫 → 拦截器 → 管道 → 控制器 → 服务 → 拦截器(后置)→ 过滤器
  3. 洋葱模型:前置拦截器和后置拦截器顺序相反
  4. 钩子方法:每个组件都是一个钩子,在特定时机执行
  5. 实践为主:不需要死记硬背,用过就会记住

行动建议

code
学习路径:
│
├──  第一阶段:理解概念(1-2 天)
│   ├── 理解三大核心概念
│   ├── 理解生命周期流程
│   └── 理解各组件职责
│
├──  第二阶段:实践练习(1 周)
│   ├── 实现中间件日志
│   ├── 实现守卫认证
│   ├── 实现拦截器转换
│   └── 实现管道验证
│
└──  第三阶段:深入应用(持续)
    ├── 理解组件执行顺序
    ├── 性能优化
    └── 最佳实践

八、延伸学习资源

官方资源

练习建议

  1. 练习 1:实现一个完整的请求日志系统(中间件 + 拦截器)
  2. 练习 2:实现 JWT 认证系统(守卫 + 服务)
  3. 练习 3:实现统一响应格式(拦截器)
  4. 练习 4:实现参数验证系统(管道 + DTO)
  5. 练习 5:实现统一异常处理(过滤器)

延伸思考

code
思考题:
│
├──  为什么要将业务逻辑放在 Service 而不是 Controller?
├──  拦截器的前置和后置为什么要相反?
├──  如何优化生命周期的性能?
├──  在什么场景下使用哪个组件?
└──  如何设计一个合理的架构?

附录:生命周期速查表

序号组件执行顺序职责
1⃣Middleware全局 → 模块日志、安全、预处理
2⃣Guard全局 → 控制器 → 路由认证、授权、访问控制
3⃣Interceptor (Before)全局 → 控制器 → 路由日志、转换、缓存
4⃣Pipe全局 → 控制器 → 路由 → 参数验证、转换、清洗
5⃣Controller Method-路由分发
6⃣Service-业务逻辑
7⃣Interceptor (After)路由 → 控制器 → 全局日志、转换、缓存
8⃣Exception Filter路由 → 控制器 → 全局异常处理

笔记整理完成时间:2026-03-07
下一章节预告:NestJS 各组件深入实践