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 对比表
| 框架 | 生命周期钩子 | 说明 |
|---|---|---|
| Vue | mounted | 组件挂载后执行 |
| React | componentDidMount | 组件挂载后执行 |
| 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() 指定异常类型 |
| 执行顺序错误 | 不了解生命周期 | 参考本文档的生命周期图 |
| 性能问题 | 组件中执行耗时操作 | 保持组件轻量,避免数据库查询 |
七、学习要点总结
核心要点
- 三大核心概念:Controller(控制器)、Service(服务)、Data Access(数据访问层)
- 请求生命周期:中间件 → 守卫 → 拦截器 → 管道 → 控制器 → 服务 → 拦截器(后置)→ 过滤器
- 洋葱模型:前置拦截器和后置拦截器顺序相反
- 钩子方法:每个组件都是一个钩子,在特定时机执行
- 实践为主:不需要死记硬背,用过就会记住
行动建议
code
学习路径:
│
├── 第一阶段:理解概念(1-2 天)
│ ├── 理解三大核心概念
│ ├── 理解生命周期流程
│ └── 理解各组件职责
│
├── 第二阶段:实践练习(1 周)
│ ├── 实现中间件日志
│ ├── 实现守卫认证
│ ├── 实现拦截器转换
│ └── 实现管道验证
│
└── 第三阶段:深入应用(持续)
├── 理解组件执行顺序
├── 性能优化
└── 最佳实践八、延伸学习资源
官方资源
- NestJS Controllers
- NestJS Providers
- NestJS Middleware
- NestJS Guards
- NestJS Interceptors
- NestJS Pipes
- NestJS Exception Filters
练习建议
- 练习 1:实现一个完整的请求日志系统(中间件 + 拦截器)
- 练习 2:实现 JWT 认证系统(守卫 + 服务)
- 练习 3:实现统一响应格式(拦截器)
- 练习 4:实现参数验证系统(管道 + DTO)
- 练习 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 各组件深入实践