20 节课系统掌握 NestJS 框架,从入门到架构设计。 基于 NestJS v11 官方文档全部 142 页 + 框架源码 42,000 行 TypeScript 设计。
课程设计原则
受众分层:每节课包含五个层次的内容,不同水平的学员在同一节课中各取所需。
| 标识 | 层次 | 画像 | 目标 |
|---|---|---|---|
[基础] | 入门 | 有 Node.js 基础,首次接触 NestJS | 能用框架写出可运行的代码 |
[中阶] | 熟练 | 能用 NestJS 完成业务开发 | 掌握最佳实践,写出规范代码 |
[高阶] | 深入 | 1 年以上 NestJS 经验 | 理解框架内部机制,能扩展框架 |
[资深] | 源码 | 希望成为框架贡献者或深度定制者 | 能读懂并修改框架源码 |
[架构] | 设计 | 技术负责人、架构师 | 能基于 NestJS 做技术选型和系统设计 |
知识依赖图:
第一阶段:核心基础(第1-4课)
第1课 ─→ 第2课 ─→ 第3课 ─→ 第4课
第二阶段:请求管线(第5-8课)
│
┌───────────────┤
▼ ▼
第5课 第6课
│ │
▼ ▼
第7课 第8课
第三阶段:DI 深入(第9课)
│ │
└───────┬───────┘
▼
第9课
第四阶段:数据与安全(第10-12课)
│
┌───────┤
▼ ▼
第10课 第11课 ─→ 第12课
第五阶段:实用技术(第13-15课)
│
┌─────────┼─────────┐
▼ ▼ ▼
第13课 第14课 第15课
第六阶段:通信与 API(第16-19课)
│ │ │
└─────────┼─────────┘
▼
第16课 ─→ 第17课
│
第18课 ─→ 第19课
第七阶段:生产(第20课)
│
▼
第20课
负载均衡:每节课覆盖 5-10 页文档、3-6 个核心主题,确保节奏均匀。
| 阶段 | 课程 | 覆盖文档页数 | 核心主题数 |
|---|---|---|---|
| 核心基础 | 第1-4课 | 4+2+3+4 = 13 | 3+3+4+5 = 15 |
| 请求管线 | 第5-8课 | 3+2+3+3 = 11 | 4+4+5+4 = 17 |
| DI 深入 | 第9课 | 5 | 6 |
| 数据与安全 | 第10-12课 | 7+4+5 = 16 | 5+5+5 = 15 |
| 实用技术 | 第13-15课 | 5+3+7 = 15 | 5+3+6 = 14 |
| 通信与 API | 第16-19课 | 6+12+18+10 = 46 | 4+5+6+5 = 20 |
| 生产 | 第20课 | 15+ | 6 |
第一课:走进 NestJS — 理念、环境与第一个应用
覆盖文档:Introduction, First Steps, CLI Overview, CLI Scripts 前置知识:Node.js 基础, TypeScript 基础
课程内容
[基础] 从零创建项目
- NestJS 是什么:基于 Node.js 的渐进式服务端框架
- 与 Express/Koa/Fastify 的关系:NestJS 是架构层,Express/Fastify 是 HTTP 引擎
- 环境准备:Node.js >= 20, Nest CLI 安装
nest new project-name创建项目- 项目目录结构解析:
main.ts→app.module.ts→app.controller.ts→app.service.ts NestFactory.create(AppModule)与app.listen(3000)- 启动与验证:
npm run start:dev,访问http://localhost:3000 - CLI 常用命令:
nest generate(18 种 schematic),nest build,nest start
[中阶] 工程化配置
- TypeScript 严格模式:
nest new --strict - SWC 编译器加速:
npm run start -- -b swc,20x 编译提速 - ESLint + Prettier 代码规范
- 热重载配置(HMR):
webpack+RunScriptWebpackPlugin nest-cli.json关键配置项:compilerOptions、generateOptions
[高阶] 平台选择与多平台抽象
- Express vs Fastify 对比:生态 vs 性能
NestFactory.create<NestExpressApplication>与NestFactory.create<NestFastifyApplication>的区别abortOnError选项的作用- 平台无关性设计思想:同一套业务逻辑可以运行在 HTTP/WebSocket/微服务/GraphQL 上
[资深] 源码:NestFactory 启动流程
- 入口文件:
packages/core/nest-factory.ts create()方法的完整流程:- 创建
NestContainer(DI 容器) - 初始化
DependenciesScanner - 初始化
InstanceLoader - 初始化
RoutesResolver - 调用生命周期钩子
- 创建
ExceptionsZone的作用:全局异常捕获区
[架构] 技术选型决策
- NestJS 适用场景:企业级 API、微服务、BFF 层、全栈应用
- 不适用场景:极简 Serverless 函数、纯静态站点
- 与 Spring Boot 的架构对比:同样的 IoC/DI 思想,不同的语言生态
- Monorepo vs 多仓:
nest g app转换 Monorepo,nest g library创建共享库 - 团队接入 NestJS 的成本评估
课后实践
- 用
nest new创建项目,确认Hello World运行正常 - 分别用 Express 和 Fastify 平台启动项目,对比差异
第二课:Controller — 请求的入口
覆盖文档:Controllers 前置知识:第1课
课程内容
[基础] 路由与请求处理
@Controller('cats')定义路由前缀- HTTP 方法装饰器:
@Get(),@Post(),@Put(),@Delete(),@Patch(),@Options(),@Head(),@All() - 路由参数:
@Param('id'),@Query('page'),@Body(),@Headers('authorization') - DTO(Data Transfer Object):用 class 定义请求体结构
- 响应状态码:
@HttpCode(204) - 响应头设置:
@Header('Cache-Control', 'no-store') - 重定向:
@Redirect('https://example.com', 301)
[中阶] 高级路由技巧
- 路由通配符:
@Get('abcd/*')匹配任意路径 - 子域名路由:
@Controller({ host: ':account.example.com' }),@HostParam('account') - 异步控制器:
async/await与 RxJSObservable两种返回方式 - 请求负载:
@Query()复杂查询参数解析(嵌套对象、数组) - Library-specific 模式:
@Res({ passthrough: true })直接操作 Express/Fastify response 对象 - 参数顺序:静态路由应声明在参数路由之前
[高阶] API 版本控制
- 4 种版本策略:URI(
/v1/cats)、Header、Media Type、Custom app.enableVersioning({ type: VersioningType.URI })- 控制器级:
@Controller({ version: '1' }) - 路由级:
@Version(['1', '2']) VERSION_NEUTRAL版本无关路由
[资深] 源码:路由注册机制
packages/common/decorators/http/request-mapping.decorator.ts:@Get/@Post如何通过Reflect.defineMetadata挂载路由信息packages/core/router/router-explorer.ts:扫描 Controller 方法,提取路由元数据packages/core/router/routes-resolver.ts:顶层路由解析协调器- Express adapter 如何将 NestJS 路由注册到底层 Express 路由表
[架构] RESTful API 设计
- 资源命名规范:名词复数(
/users),避免动词 - HTTP 方法语义:GET 幂等、POST 创建、PUT 全量更新、PATCH 部分更新、DELETE 删除
- 状态码选择策略:200/201/204/400/401/403/404/409/422/500
- 全局路径前缀:
app.setGlobalPrefix('api/v1'),排除健康检查路由 - CRUD 代码生成:
nest g resource cats一键生成完整 CRUD 结构
课后实践
- 实现一个完整的
CatsController:包含 CRUD 五个方法 - 尝试用
@Query()实现分页(page, limit)和过滤(breed, age) - 用
nest g resource dogs对比手写 vs 自动生成
第三课:Provider 与依赖注入 — 框架的灵魂
覆盖文档:Providers, Custom Providers, Async Providers 前置知识:第2课
课程内容
[基础] Service 与构造器注入
@Injectable()装饰器:声明一个类可被 DI 容器管理- 构造器注入:
constructor(private catsService: CatsService) {} - TypeScript 的
private简写同时完成声明和赋值 - Service 的职责:封装业务逻辑,Controller 只做路由分发
- Provider 注册:
@Module({ providers: [CatsService] }) @Optional()可选依赖:未提供时不报错
[中阶] 四种 Provider 模式
- useClass:默认模式,注册一个类
{ provide: CatsService, useClass: CatsService } // 等价于直接写 CatsService - useValue:注入常量、配置对象、Mock 对象
{ provide: 'API_KEY', useValue: 'abc123' } - useFactory:工厂函数,可注入其他依赖、支持异步
{ provide: 'DB_CONNECTION', useFactory: async (config) => createConnection(config), inject: [ConfigService] } - useExisting:别名,两个 token 指向同一实例
- 非类 token(string/Symbol)需要
@Inject('TOKEN')注入 - 属性注入:
@Inject('HTTP_OPTIONS') private httpClient: T(不推荐,优先用构造器)
[高阶] 异步 Provider 与条件 Provider
- 异步 Provider:
useFactory返回Promise,启动时等待解析完成 - 运行时条件选择:
useClass根据环境变量选择不同实现类 NEST_DEBUG=true查看依赖解析日志- Provider 导出:
exports: [CatsService]使其对导入模块可用
[资深] 源码:DI 容器实现
packages/core/injector/container.ts:NestContainer— 顶层容器,管理所有 Modulepackages/core/injector/module.ts:每个 Module 内部维护_providers、_controllers、_imports、_exports四个 Mappackages/core/injector/instance-wrapper.ts:InstanceWrapper— 每个 provider 的元数据封装(实例、scope、依赖列表、是否已解析)packages/core/injector/injector.ts:resolveComponentInstance()— 依赖解析核心算法- Provider token 的解析顺序:类型 → 自定义 token → forwardRef
[架构] IoC/DI 设计模式
- 控制反转(IoC)的本质:对象的创建和生命周期管理交给容器
- 依赖倒置原则(DIP):高层模块不依赖低层模块,都依赖抽象
- NestJS vs Spring:构造器注入 vs 字段注入的取舍
- interface 在 NestJS 中的局限:TypeScript interface 编译后消失,需要用 class 或自定义 token
- 何时使用 useFactory vs useClass:有条件逻辑或异步初始化时用 Factory
课后实践
- 创建
CatsService注入到CatsController,实现内存数据的 CRUD - 用
useValue注入一个 mock 数据源,用useFactory注入一个异步初始化的数据库连接 - 用
NEST_DEBUG=true观察依赖解析过程
第四课:Module 系统 — 应用的组织骨架
覆盖文档:Modules, Dynamic Modules, Lazy-loading Modules, CLI Workspaces, CLI Libraries 前置知识:第3课
课程内容
[基础] 模块基础
@Module()四大属性:imports、controllers、providers、exports- 根模块
AppModule:整个应用的入口 - 功能模块:按业务域组织代码(
UsersModule、OrdersModule) nest g module cats快速创建模块- 模块注册:在
AppModule的imports中引入功能模块
[中阶] 模块间共享与全局模块
- 共享模块:通过
exports导出 provider,其他模块imports后即可使用 - 模块单例性:同一模块在多处导入,provider 共享同一实例
- 模块重导出:
exports: [CommonModule]让导入者间接获得 CommonModule 的能力 @Global()全局模块:注册一次全应用可用(慎用,推荐显式 imports)- 模块内注入:模块类本身可以注入 provider(用于配置)
[高阶] 动态模块
- 静态模块 vs 动态模块:固定配置 vs 运行时配置
forRoot()/forFeature()/register()命名约定:forRoot():全局配置一次(如数据库连接)forFeature():功能模块按需注册(如实体/模型)register():每个消费者独立配置
- 动态模块返回
DynamicModule对象:{ module, providers, exports } ConfigurableModuleBuilder<T>:自动生成register()/registerAsync()的基类MODULE_OPTIONS_TOKEN:自动生成的配置注入 token.setClassMethodName('forRoot')自定义方法名.setExtras({ isGlobal: true }, ...)添加额外选项
forRootAsync()异步配置:useFactory/useClass/useExisting
[资深] 源码:模块扫描与编译
packages/core/scanner.ts:DependenciesScannerscanForModules():递归扫描@Module()的imports,构建模块树scanModulesForDependencies():解析每个模块的 providers/controllers/exports- 处理
DynamicModule:调用forRoot()等静态方法获取运行时配置
packages/core/injector/compiler.ts:模块编译器,处理动态模块的合并packages/common/module-utils/configurable-module.builder.ts:ConfigurableModuleBuilder的实现- 懒加载:
packages/core/injector/lazy-module-loader/lazy-module-loader.ts
[架构] 模块化架构设计
- 模块边界设计:高内聚、低耦合
- 分层架构模式:
AppModule ├── CoreModule(全局单例:Logger、Config、Guards) ├── SharedModule(共享工具:HttpModule、CacheModule) ├── AuthModule(认证/授权) ├── UsersModule(用户域) ├── OrdersModule(订单域) └── PaymentsModule(支付域) - Monorepo 管理:
nest g app admin-api创建多应用,nest g library shared创建共享库 - 懒加载在 Serverless 场景的价值:减少冷启动时间
RouterModule:模块级路由前缀RouterModule.register([{ path: 'admin', module: AdminModule }])
课后实践
- 将第2、3课的代码重构为
CatsModule,确保CatsService被正确导出和共享 - 创建一个
DatabaseModule.forRoot(config)动态模块 - 用
ConfigurableModuleBuilder重写上述动态模块,体会自动生成的便利
第五课:中间件与异常处理 — 请求管线第一层
覆盖文档:Middleware, Exception Filters, 内置异常类 前置知识:第4课
课程内容
[基础] 中间件基础
- 中间件的职责:在路由处理器之前执行,可访问
req/res/next() - 类中间件:实现
NestMiddleware接口,use(req, res, next)方法 - 函数中间件:简单场景下更简洁,无需 class
- 注册中间件:模块实现
NestModule接口,在configure(consumer)中使用MiddlewareConsumer forRoutes()绑定路由:字符串、路由对象{ path, method }、Controller 类exclude()排除路由
[中阶] 中间件进阶
- 多中间件:
consumer.apply(cors(), helmet(), logger).forRoutes(CatsController) - 全局中间件:
app.use(logger)— 无法使用 DI - 类中间件的 DI 能力:可通过构造器注入其他 provider
- 通配符路由:
forRoutes({ path: 'abcd/*splat', method: RequestMethod.ALL }) - Express vs Fastify 中间件差异:Fastify 中间件接收原始
req/res
[基础] 异常基础
HttpException:手动抛出throw new HttpException('Forbidden', HttpStatus.FORBIDDEN)- 内置异常类(24 种):
BadRequestException、UnauthorizedException、NotFoundException、ForbiddenException、ConflictException、InternalServerErrorException等 - 异常响应格式:
{ statusCode, message, error } - 自定义异常:继承
HttpException cause参数:传递底层错误用于日志记录
[中阶] 异常过滤器
@Catch(HttpException)+ExceptionFilter接口:自定义异常响应格式ArgumentsHost:host.switchToHttp()获取request和response- 绑定范围:方法级
@UseFilters()、控制器级、全局级app.useGlobalFilters() APP_FILTERtoken 注册全局 filter(支持 DI)- 全捕获过滤器:
@Catch()不传参数,捕获所有异常
[高阶] 平台无关异常处理
HttpAdapterHost:通过 HTTP 适配器抽象响应,不直接操作 Express/Fastify responseBaseExceptionFilter:继承内置 filter 并扩展- 异常日志策略:
IntrinsicException标记为"正常流程异常",默认不打日志
[资深] 源码:异常处理机制
packages/core/exceptions/exceptions-zone.ts:ExceptionsZone.run()的全局 try-catchpackages/core/exceptions/base-exception-filter.ts:默认异常过滤器实现packages/common/exceptions/http.exception.ts:HttpException基类packages/common/exceptions/intrinsic.exception.ts:标记内置异常,影响日志行为- 异常过滤器的解析顺序:路由级 → 控制器级 → 全局级
[架构] 错误处理策略
- 统一错误响应格式:
{ code, message, timestamp, path } - 业务异常 vs 系统异常:业务异常(400-499)不该触发告警,系统异常(500)必须告警
- 错误监控集成:Sentry(
@sentry/nestjs) - 敏感信息隔离:生产环境异常不暴露堆栈
课后实践
- 实现一个
LoggerMiddleware,记录每个请求的 method、url、耗时 - 实现一个
AllExceptionsFilter,统一返回{ code, message, timestamp, path }格式 - 将 filter 通过
APP_FILTER注册为全局 filter,注入HttpAdapterHost
第六课:Pipes — 数据的验证与转换
覆盖文档:Pipes, Validation(Techniques) 前置知识:第5课
课程内容
[基础] 内置管道
- Pipe 的两大用途:验证(数据是否合法)和转换(数据类型转换)
- 10 个内置管道:
ParseIntPipe、ParseFloatPipe、ParseBoolPipe、ParseUUIDPipe、ParseEnumPipe、ParseArrayPipe、ParseDatePipe、DefaultValuePipe、ParseFilePipe、ValidationPipe - 参数级绑定:
@Param('id', ParseIntPipe) id: number - 错误响应示例:传入非数字时返回
400 Bad Request - 自定义错误码:
new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE })
[中阶] class-validator 验证
class-validator+class-transformer:声明式验证- DTO 装饰器:
@IsString(),@IsInt(),@IsEmail(),@IsNotEmpty(),@Min(),@Max(),@IsOptional() ValidationPipe全局注册:app.useGlobalPipes(new ValidationPipe())- 关键选项:
whitelist: true:自动剥离未装饰的属性forbidNonWhitelisted: true:未知属性直接报错transform: true:自动转换为 DTO 实例 + 基本类型转换disableErrorMessages: true:生产环境隐藏详细验证错误
- 映射类型工具:
PartialType()、PickType()、OmitType()、IntersectionType()(来自@nestjs/mapped-types)
[中阶] Zod 验证
- Zod schema 定义:
z.object({ name: z.string(), age: z.number() }).required() ZodValidationPipe:自定义管道调用schema.parse(value)@UsePipes(new ZodValidationPipe(schema))绑定到方法- Zod vs class-validator 对比:Zod 更函数式,class-validator 更声明式
[高阶] 自定义管道与转换管道
PipeTransform<T, R>接口:transform(value: T, metadata: ArgumentMetadata): RArgumentMetadata:type(body/query/param/custom),metatype(类型类),data(装饰器参数名)- 转换管道用例:
UserByIdPipe— 传入 id,返回完整 UserEntity - 管道执行顺序:全局 → 控制器 → 路由 → 参数级,参数从最后一个到第一个
APP_PIPEtoken 注册全局管道(支持 DI)
[资深] 源码:管道执行机制
packages/common/pipes/:10 个内置管道的实现packages/common/pipes/validation.pipe.ts:ValidationPipe内部调用class-transformer的plainToInstance()和class-validator的validate()packages/core/pipes/pipes-consumer.ts:管道的串联执行逻辑- 管道在请求管线中的位置:Guard 之后、Controller 之前
[架构] 验证策略选型
- 单一验证层 vs 多层验证:API 边界必须验证,内部服务间信任
- class-validator 适合:DTO 驱动、装饰器风格团队
- Zod 适合:函数式风格、前后端共享 schema
- 验证与业务规则分离:Pipe 做格式验证,Guard/Service 做业务规则校验
- 文件验证:
ParseFilePipe+MaxFileSizeValidator+FileTypeValidator
课后实践
- 为
CreateCatDto添加 class-validator 装饰器,全局启用ValidationPipe({ whitelist: true, transform: true }) - 用
PartialType(CreateCatDto)创建UpdateCatDto - 实现一个
CatByIdPipe:传入 id,从 CatsService 中查找并返回 Cat 实体
第七课:Guards 与 Interceptors — 权限控制与 AOP
覆盖文档:Guards, Interceptors, Execution Context 前置知识:第6课
课程内容
[基础] Guards 守卫
- Guard 的职责:决定请求是否被允许继续处理(authorization)
CanActivate接口:canActivate(context: ExecutionContext): boolean | Promise<boolean>- 返回
true放行,返回false自动抛出ForbiddenException - 绑定方式:
@UseGuards(AuthGuard)— 方法级、控制器级 - 全局绑定:
app.useGlobalGuards()或APP_GUARDtoken
[中阶] 角色守卫实战
Reflector.createDecorator<string[]>()创建@Roles(['admin'])装饰器RolesGuard:通过Reflector.get()读取当前路由的角色元数据ExecutionContext:继承ArgumentsHost,增加getHandler()(当前方法)和getClass()(控制器类)- Guard vs Middleware:Guard 知道下一步要执行什么(有 ExecutionContext),Middleware 不知道
- Guard 执行顺序:全局 → 控制器 → 路由
[基础] Interceptors 拦截器
- 拦截器的能力(AOP):
- 在方法执行前后绑定逻辑
- 转换返回结果
- 转换抛出的异常
- 扩展基本方法行为
- 完全覆盖方法(如缓存)
NestInterceptor接口:intercept(context: ExecutionContext, next: CallHandler): Observable<any>CallHandler.handle():调用路由处理器,返回 RxJS Observable
[中阶] 拦截器实战
- 日志拦截器:
tap()操作符记录请求前后的时间差 - 响应映射:
map(data => ({ data }))统一包装响应格式 - 异常映射:
catchError()转换异常类型 - 超时控制:
timeout(5000)+catchError处理TimeoutError - 缓存拦截器:
of([])直接返回缓存值,跳过 handler - 绑定方式:
@UseInterceptors()— 方法级、控制器级、全局级 /APP_INTERCEPTOR - 拦截器执行顺序:入方向 全局→控制器→路由,出方向 路由→控制器→全局(反序)
[高阶] ExecutionContext 与 Reflector 深入
ArgumentsHost:switchToHttp()、switchToRpc()、switchToWs()— 跨平台上下文切换ExecutionContext:getHandler()获取当前方法引用,getClass()获取控制器类Reflector三种读取方式:.get(decorator, target):从单个目标读取.getAllAndOverride(key, [handler, class]):方法级覆盖类级.getAllAndMerge(key, [handler, class]):合并方法级和类级
[资深] 源码:管线组装
packages/core/router/router-execution-context.ts:核心文件,组装 Guard → Interceptor → Pipe → Handler 管线packages/core/guards/guards-consumer.ts:Guard 链的执行packages/core/interceptors/interceptors-consumer.ts:Interceptor 链的执行- Guard 如何获取
ExecutionContext:框架在调用canActivate时注入
[架构] 横切关注点设计
- Guard 做权限,Interceptor 做日志/缓存/转换 — 职责分离
- 全局 vs 模块级增强器:
APP_GUARD/APP_INTERCEPTOR支持 DI,useGlobalXxx不支持 - 跨上下文统一(HTTP/WS/RPC/GraphQL):同一套 Guard/Interceptor 可复用
- 性能考量:过多 Interceptor 链增加请求延迟
课后实践
- 实现 JWT
AuthGuard:从 Authorization header 提取 token 并验证 - 实现
@Roles(['admin'])装饰器 +RolesGuard:基于角色的路由保护 - 实现
TransformInterceptor:统一响应为{ data, timestamp }格式 - 实现
TimeoutInterceptor:5 秒超时自动返回 408
第八课:自定义装饰器与元数据编程
覆盖文档:Custom Decorators, Custom Providers(进阶部分), Discovery Service 前置知识:第7课
课程内容
[基础] 自定义参数装饰器
createParamDecorator((data, ctx: ExecutionContext) => ...)- 示例:
@User()从请求中提取用户信息 - 传递数据参数:
@User('email')提取用户特定属性 - 自定义装饰器与 Pipe 配合:
@User(new ValidationPipe({ validateCustomDecorators: true }))
[中阶] 装饰器组合
applyDecorators(...decorators):将多个装饰器合并为一个- 示例:
@Auth('admin')=@SetMetadata('roles', ['admin'])+@UseGuards(AuthGuard, RolesGuard)+@ApiBearerAuth() @SetMetadata(key, value):低层级元数据设置- 类装饰器 vs 方法装饰器 vs 参数装饰器的区别
[高阶] Discovery Service 运行时内省
DiscoveryModule+DiscoveryService(from@nestjs/core).getProviders():获取所有已注册 provider 及其元数据.getControllers():获取所有 controller- 按装饰器过滤:基于自定义装饰器找出特定 provider
- 应用场景:插件自动发现、自动注册事件处理器、运行时生成路由表
[资深] 源码:装饰器与 Reflect Metadata
- TypeScript
emitDecoratorMetadata编译选项的作用 Reflect.defineMetadata/Reflect.getMetadata/Reflect.getOwnMetadatapackages/common/constants.ts:所有内置元数据 key(CONTROLLER_WATERMARK、INJECTABLE_WATERMARK、MODULE_METADATA等)- 装饰器如何被 Scanner 和 Router 消费:运行时读取元数据 → 构建依赖图/路由表
packages/core/discovery/discovery-service.ts:DiscoveryService 的实现
[架构] 元数据驱动架构
- 声明式编程的优势:配置即代码,减少样板
- 装饰器模式在企业级框架中的应用:Spring Annotations vs NestJS Decorators vs Python Decorators
- 自定义装饰器的设计原则:单一职责,可组合
- 利用 Discovery Service 构建插件系统
课后实践
- 实现
@Public()装饰器标记无需认证的路由,修改AuthGuard通过 Reflector 跳过公开路由 - 实现
@Auth('admin', 'editor')组合装饰器 - 使用 DiscoveryService 在应用启动时列出所有带
@Cacheable()装饰器的方法
第九课:注入作用域与应用生命周期
覆盖文档:Injection Scopes, Circular Dependency, Module Reference, Lifecycle Events, Platform Agnosticism 前置知识:第8课
课程内容
[基础] 三种注入作用域
Scope.DEFAULT(Singleton):默认,全应用共享一个实例Scope.REQUEST:每个请求创建新实例,请求结束后销毁Scope.TRANSIENT:每次注入创建新实例- 设置方式:
@Injectable({ scope: Scope.REQUEST }) REQUESTtoken:在 Request-scoped provider 中注入原始请求对象
[中阶] Scope 冒泡与生命周期
- Scope 冒泡规则:如果 Service 是 Request-scoped,依赖它的 Controller 也变成 Request-scoped
- 性能影响:Request-scoped 每次请求都创建/销毁实例链,影响性能
INQUIRERtoken:Transient provider 中获取"谁注入了我"- 生命周期钩子(按执行顺序):
onModuleInit():模块依赖解析完成onApplicationBootstrap():所有模块初始化完成,开始监听前onModuleDestroy():收到终止信号beforeApplicationShutdown(signal):所有onModuleDestroy完成后onApplicationShutdown(signal):连接关闭后
app.enableShutdownHooks():必须显式启用终止钩子
[高阶] 循环依赖与 ModuleRef
- 循环依赖解决:
forwardRef(() => CatService)— Provider 间和 Module 间都适用 - 避免 barrel file(index.ts)导致的虚假循环依赖
ModuleRef:运行时动态访问 DI 容器.get(token):获取 Singleton 实例.resolve(token, contextId):获取 Scoped 实例.create(Class):在容器外动态实例化一个类
ContextIdFactory:创建/获取上下文 ID- 持久提供者(Durable Providers):多租户场景,按租户缓存 DI 子树
[资深] 源码:作用域与生命周期实现
packages/core/injector/instance-wrapper.ts:Scope 属性如何影响实例创建packages/core/injector/injector.ts:Singleton vs Request vs Transient 的解析路径分支packages/core/nest-application-context.ts:生命周期钩子的执行引擎packages/core/hooks/:钩子的调用逻辑packages/core/injector/module-ref.ts:ModuleRef 的实现
[架构] 多租户与请求隔离架构
- Singleton 为主、Request-scoped 为辅的原则
- 替代 Request-scoped 的方案:
AsyncLocalStorage(nestjs-cls包),无 scope 冒泡开销 - 持久提供者在多租户 SaaS 中的应用
- 优雅关闭策略:
enableShutdownHooks+beforeApplicationShutdown中等待进行中的请求完成 - 平台无关性:同一套 Guard/Pipe/Interceptor 在 HTTP/WS/RPC/GraphQL 中复用
课后实践
- 创建一个 Request-scoped 的
RequestLoggerService,注入REQUEST获取请求信息 - 实现
onModuleInit在模块启动时打印配置信息 - 用
ModuleRef.resolve()验证 Transient provider 每次返回不同实例
第十课:数据持久化 — 数据库集成全方案
覆盖文档:Database, MongoDB, Serialization, Recipes(TypeORM/Mongoose/Prisma/MikroORM/Sequelize) 前置知识:第9课 文档页数:7 页 | 核心主题:5
课程内容
[基础] TypeORM 集成
- 安装:
@nestjs/typeorm+typeorm+ 数据库驱动(mysql2/pg) TypeOrmModule.forRoot({ type, host, port, username, password, database, entities, synchronize })- 实体定义:
@Entity()+@Column()+@PrimaryGeneratedColumn() TypeOrmModule.forFeature([CatEntity]):按模块注册实体@InjectRepository(CatEntity):注入Repository<CatEntity>- 基本 CRUD:
.find(),.findOneBy(),.save(),.remove() autoLoadEntities: true:自动发现forFeature注册的实体
[中阶] Mongoose 与 Prisma
- Mongoose 集成:
MongooseModule.forRoot('mongodb://...')- Schema 定义:
@Schema()+@Prop()装饰器 MongooseModule.forFeature([{ name: Cat.name, schema: CatSchema }])@InjectModel(Cat.name)注入Model<Cat>- Hook、Plugin、Discriminator(Schema 继承)
- Prisma 集成:
- Schema 文件定义模型,
npx prisma generate生成类型安全客户端 PrismaService extends PrismaClient,直接注入使用- 类型安全的 CRUD:
prisma.cat.findMany(),.create(),.update()
- Schema 文件定义模型,
[高阶] 数据层进阶
- 多数据库连接:
TypeOrmModule.forRoot({ name: 'secondary', ... }) - 异步配置:
forRootAsync({ useFactory, inject: [ConfigService] }) - 事务处理:TypeORM
QueryRunner,Sequelizesequelize.transaction() - 序列化控制(
class-transformer):@Exclude()隐藏密码等敏感字段@Expose()计算属性@Transform()自定义转换ClassSerializerInterceptor全局启用
- MikroORM:Data Mapper + Unit of Work 模式,
@CreateRequestContext()自动请求上下文 synchronize: true仅限开发环境,生产必须用 migration
[资深] 源码与 Provider 模式
@nestjs/typeorm的forRoot/forFeature是动态模块的经典实现getRepositoryToken(Entity)用于测试时 mock Repository- 自定义 Repository 实现
- TypeORM EntitySubscriber:实体事件监听
[架构] 数据层架构选型
-
ORM 对比:
特性 TypeORM Prisma Mongoose MikroORM Sequelize 模式 Active Record + Data Mapper 声明式 Schema Schema + Model Data Mapper + UoW Active Record 类型安全 中 强 弱 强 中 迁移 内置 内置(优秀) 无 内置 内置 适用 SQL 全场景 新项目首选 MongoDB 复杂域模型 遗留项目 -
Repository 模式 vs Active Record:NestJS 推荐 Repository
-
读写分离、连接池配置
-
测试策略:mock Repository vs 真实数据库(内存数据库/Testcontainers)
课后实践
- 选择一种 ORM,为 CatsModule 添加真实数据库持久化
- 实现
@Exclude()隐藏 password 字段,ClassSerializerInterceptor全局启用 - 编写单元测试,mock
Repository<CatEntity>
第十一课:认证与授权 — 身份验证体系
覆盖文档:Authentication, Authorization, Passport(Recipe) 前置知识:第7课(Guards)、第10课 文档页数:4 页 | 核心主题:5
课程内容
[基础] JWT 认证
- 认证流程:用户名/密码登录 → 服务端验证 → 签发 JWT → 客户端携带 Bearer Token → 服务端验证 Token
@nestjs/jwt:JwtModule.register({ global: true, secret, signOptions: { expiresIn } })AuthService.signIn():验证凭据 +jwtService.signAsync(payload)AuthGuard:从Authorization: Bearer xxx提取 token,jwtService.verifyAsync()验证- 全局启用:
{ provide: APP_GUARD, useClass: AuthGuard } @Public()装饰器:标记公开路由跳过认证
[中阶] Passport 集成与密码安全
- Passport 策略模式:
PassportStrategy(Strategy)继承 +validate()方法 LocalStrategy:用户名/密码本地验证JwtStrategy:JWT token 自动解码和验证AuthGuard('local')和AuthGuard('jwt')的使用- 密码哈希:
bcrypt.hash(password, salt)和bcrypt.compare(plain, hashed) - 不要明文存储密码,不要在日志中打印密码
[中阶] 授权(RBAC)
- 角色枚举:
enum Role { User = 'user', Admin = 'admin' } @Roles(Role.Admin)+RolesGuard+Reflector- 权限合并策略:
getAllAndOverride(方法级覆盖类级) vsgetAllAndMerge(合并)
[高阶] CASL 细粒度权限
- CASL(Attribute-based Access Control):
CaslAbilityFactory定义能力 PoliciesGuard+@CheckPolicies(handler)装饰器- Policy Handler:回调函数式或类实现
IPolicyHandler接口 - 字段级权限控制
[资深] 认证源码解析
AuthGuard如何通过Reflector读取@Public()元数据跳过认证@nestjs/jwt的JwtModule是ConfigurableModuleBuilder的实际应用- Passport 策略的适配器模式
[架构] 认证架构设计
- 认证 vs 授权:认证回答"你是谁",授权回答"你能做什么"
- Token 刷新策略:Access Token(短期) + Refresh Token(长期)
- 零信任架构:每个微服务独立验证 Token
- 敏感操作二次验证
课后实践
- 实现完整的 JWT 认证流程:注册 → 登录 → 受保护路由
- 添加
@Roles()+RolesGuard实现基于角色的访问控制 - 用 Passport 实现 Local + JWT 双策略认证
第十二课:安全加固 — 防御纵深
覆盖文档:Encryption and Hashing, Helmet, CORS, CSRF Protection, Rate Limiting 前置知识:第11课 文档页数:5 页 | 核心主题:5
课程内容
[基础] Helmet 与 CORS
- Helmet:
app.use(helmet())— 设置 15+ 安全响应头(CSP、X-Frame-Options 等) - Helmet 必须在其他中间件之前注册
- Fastify 使用
@fastify/helmet:app.register(helmet) - CORS:
app.enableCors({ origin, methods, credentials })或NestFactory.create(AppModule, { cors: true }) - CORS 配置选项:
origin(白名单)、methods、allowedHeaders、credentials
[中阶] CSRF 防护与限流
- CSRF:
csrf-csrf包实现双重提交 Cookie 模式- 需要先注册
cookie-parser或 session 中间件 doubleCsrfProtection作为全局中间件- Fastify:使用
@fastify/csrf-protection
- 需要先注册
- 限流:
@nestjs/throttlerThrottlerModule.forRoot([{ name: 'short', ttl: 1000, limit: 3 }, { name: 'long', ttl: 60000, limit: 100 }]){ provide: APP_GUARD, useClass: ThrottlerGuard }@SkipThrottle()跳过限流,@Throttle({ short: { ttl, limit } })自定义限流- 时间助手:
seconds(1),minutes(1),hours(1) - 多限流策略同时生效(short/medium/long)
- 自定义存储后端(Redis)用于分布式限流
[高阶] 加密与哈希
- 加密 vs 哈希:加密可逆(AES),哈希不可逆(bcrypt/argon2)
- 对称加密:AES-256-CTR,
crypto.createCipheriv/createDecipheriv - 密钥派生:
crypto.scrypt(password, salt, keylen) - 随机 IV:
crypto.randomBytes(16) - 密码哈希:
bcrypt.hash(password, saltRounds)和bcrypt.compare(plain, hashed)
[资深] Node.js crypto 模块深入
crypto.scryptvscrypto.pbkdf2:两种密钥派生算法对比- 安全随机数生成:
crypto.randomBytesvsMath.random - JWT secret 安全性:长度、复杂度、轮换策略
[架构] 安全架构设计
- 安全防护清单:HTTPS + Helmet + CORS + CSRF + Rate Limiting + 输入验证
- 分层防御策略:网络层(WAF/CDN)→ 传输层(TLS)→ 应用层(NestJS Guards)→ 数据层(加密存储)
- 安全审计与合规要求
- 定期依赖漏洞扫描:
npm audit
课后实践
- 为应用配置 Helmet + CORS + ThrottlerGuard 完整安全组合
- 实现密码哈希注册/登录流程(bcrypt)
- 测试限流效果:用快速请求触发 429 Too Many Requests
第十三课:配置、日志与事件 — 应用基础设施
覆盖文档:Configuration, Logger, Events, Cookies, Session 前置知识:第9课(Dynamic Modules) 文档页数:5 页 | 核心主题:5
课程内容
[基础] 配置管理
@nestjs/config:基于dotenv,ConfigModule.forRoot({ isGlobal: true })ConfigService.get<string>('DATABASE_HOST')- 类型安全:
get('port', { infer: true }) .env文件 + 环境变量优先级:运行时环境变量 > .env 文件
[中阶] 配置进阶
- 命名空间:
registerAs('database', () => ({ host, port })) ConfigModule.forFeature(databaseConfig):功能模块局部配置- Joi Schema 验证:
validationSchema: Joi.object({ PORT: Joi.number().default(3000) }) - 自定义 YAML 配置文件:
js-yaml加载 expandVariables: true:支持环境变量插值${DB_HOST}ConditionalModule.registerWhen():基于环境变量条件加载模块
[基础] 日志系统
- 内置
Logger类:private readonly logger = new Logger(MyService.name) - 日志级别:
log,error,warn,debug,verbose,fatal(级联) - 禁用/过滤日志:
NestFactory.create(AppModule, { logger: ['error', 'warn'] }) ConsoleLoggerJSON 输出:new ConsoleLogger({ json: true })— 适合日志聚合
[中阶] 自定义 Logger 与事件驱动
- 自定义 Logger:实现
LoggerService接口或继承ConsoleLogger - DI 注入自定义 Logger:
app.useLogger(app.get(MyLogger))+bufferLogs: true - Transient scope 实现每个 Service 独立 Logger 实例
- 事件驱动:
@nestjs/event-emitter(wrapseventemitter2)EventEmitterModule.forRoot()- 发射:
eventEmitter.emit('order.created', payload) - 监听:
@OnEvent('order.created'),通配符:@OnEvent('order.*')
[中阶] Cookie 与 Session
- Cookie:
cookie-parser(Express)/@fastify/cookie(Fastify),自定义@Cookies()装饰器 - Session:
express-session(Express)/@fastify/secure-session(Fastify)@Session()装饰器访问会话- 生产环境必须使用外部 session store(Redis)
[资深] 源码:ConfigModule 实现
@nestjs/config是ConfigurableModuleBuilder的典型应用registerAs()的实现:命名空间 token 生成ConfigService.get()的类型推断机制
[架构] 配置与日志架构
- 12-Factor App 原则:环境变量优先,不硬编码
- 结构化 JSON 日志 → ELK/Datadog 集中收集
- 关联 ID(Correlation ID):贯穿请求全链路的唯一标识
- 日志分级策略:开发用 debug/verbose,生产只用 log/warn/error
课后实践
- 用
@nestjs/config将数据库配置从硬编码改为.env文件驱动 - 实现自定义
FileLogger(继承 ConsoleLogger,写入文件) - 用 EventEmitter 实现"用户注册后发送欢迎邮件"的解耦场景
第十四课:异步处理 — 缓存、队列与定时任务
覆盖文档:Caching, Queues, Task Scheduling 前置知识:第13课 文档页数:3 页 | 核心主题:3(每个主题深度讲解)
课程内容
[基础] 缓存
@nestjs/cache-manager(基于cache-manager+ Keyv)CacheModule.register({ ttl: 5000, isGlobal: true })- 手动操作:
@Inject(CACHE_MANAGER) cacheManager: Cache,.get()/.set()/.del()/.clear() CacheInterceptor自动缓存 GET 请求@CacheKey('custom_key')和@CacheTTL(10000)覆盖默认值
[中阶] Redis 缓存后端
- Redis 后端:
@keyv/redis包 - 多级缓存:内存 + Redis 组合
- 自定义
CacheInterceptor:覆盖trackBy()实现自定义缓存键 - 异步配置:
CacheModule.registerAsync({ useFactory, inject: [ConfigService] })
[基础] 定时任务
@nestjs/schedule:ScheduleModule.forRoot()@Cron('45 * * * * *')/@Cron(CronExpression.EVERY_10_SECONDS)@Interval(10000)重复执行 /@Timeout(5000)延迟一次执行- Cron 选项:
name,timeZone,waitForCompletion,disabled
[中阶] 动态调度管理
SchedulerRegistry:getCronJob(name),addCronJob(),deleteCronJob()- 动态创建/停止/重启定时任务
setTime()运行时修改调度时间- 异常自动捕获并记录日志
[中阶] 消息队列
@nestjs/bullmq+ RedisBullModule.forRoot({ connection: { host, port } })BullModule.registerQueue({ name: 'audio' })- Producer:
@InjectQueue('audio'),queue.add('transcode', data, { priority, delay, attempts }) - Consumer:
@Processor('audio')+WorkerHost,实现process(job)方法 - Job 选项:
priority,delay,attempts,backoff,repeat,removeOnComplete
[高阶] 队列进阶
- Worker 事件:
@OnWorkerEvent('active'|'completed'|'failed') - Queue 事件:
@QueueEventsListener('audio')+@OnQueueEvent('waiting') - Flow Producer:父子 Job 关系(
BullModule.registerFlowProducer) - Request-scoped Consumer:
scope: Scope.REQUEST - 独立进程执行:
processors选项实现沙箱化 Job 处理
[资深] 源码:调度与队列机制
@nestjs/schedule内部使用cron包@Cron装饰器通过DiscoveryService自动发现并注册- BullMQ 的 Redis 数据结构:Sorted Set 实现延迟队列
[架构] 异步处理架构
- 同步 vs 异步处理:用户请求中不应执行耗时任务
- 缓存策略:Cache-Aside(旁路缓存)vs Read-Through vs Write-Behind
- 队列选型:BullMQ(Redis,中等规模)vs RabbitMQ(可靠投递)vs Kafka(大规模流处理)
- 幂等性设计:队列消费者必须处理重复消息
课后实践
- 用
CacheInterceptor缓存 GET /cats 接口,Redis 作后端 - 实现
@Cron定时任务定期清理过期数据 - 用 BullMQ 实现图片异步转码:API 接收上传 → 入队 → Worker 处理 → 通知完成
第十五课:文件、HTTP 与其他实用技术
覆盖文档:File Upload, Streaming Files, HTTP Module, Server-Sent Events, Compression, MVC, Serve Static, Versioning(回顾) 前置知识:第13课 文档页数:7 页 | 核心主题:6
课程内容
[基础] 文件上传
- Multer(Express only,Fastify 不兼容)
- 单文件:
@UseInterceptors(FileInterceptor('file'))+@UploadedFile() - 多文件:
FilesInterceptor('files', 10)+@UploadedFiles() - 多字段:
FileFieldsInterceptor([{ name: 'avatar', maxCount: 1 }, { name: 'photos', maxCount: 5 }]) - 验证:
ParseFilePipe+MaxFileSizeValidator+FileTypeValidator(基于 magic bytes) ParseFilePipeBuilder流式构建验证规则MulterModule.register({ dest: './uploads' })配置默认上传目录
[中阶] 流式传输与 HTTP 客户端
- 流式文件传输:
new StreamableFile(readStream)— 跨平台文件下载- 构造函数接受
Buffer或Stream - 选项:
type(Content-Type),disposition(Content-Disposition),length
- 构造函数接受
- HTTP 客户端:
@nestjs/axios(wraps Axios)HttpModule.register({ timeout: 5000, maxRedirects: 5 })httpService.get<T>(url)返回Observable<AxiosResponse<T>>- 转 Promise:
firstValueFrom(httpService.get(url)) - 直接 Axios:
httpService.axiosRef获取原生实例
[中阶] SSE 与其他技术
- Server-Sent Events:
@Sse('events')+ 返回Observable<MessageEvent>MessageEvent:data(必须),id,type,retry- 客户端:
new EventSource('/sse')
- 压缩:
compression(Express)/@fastify/compress(Fastify),生产推荐 Nginx 层处理 - MVC 渲染:
app.setViewEngine('hbs')+@Render('index')- Express:
useStaticAssets()+setBaseViewsDir()+setViewEngine() - Fastify:
@fastify/view+@fastify/static
- Express:
- 静态文件:
@nestjs/serve-static—ServeStaticModule.forRoot({ rootPath })
[高阶] 跨技术的通用配置模式
forRoot()/forRootAsync()/forFeature()是所有技术模块的统一配置模式registerAsync({ useFactory, inject: [ConfigService] })实现配置驱动- 全局 vs 模块级注册的权衡
extraProviders选项向模块注入额外依赖
[资深] 源码:StreamableFile 实现
packages/common/file-stream/streamable-file.ts:跨平台文件流抽象- Express 和 Fastify 对文件流的不同处理方式
[架构] 文件与通信策略
- 大文件上传:分片上传 + 断点续传 + 对象存储(S3/OSS)
- SSE vs WebSocket vs 轮询:SSE 适合单向服务器推送,WebSocket 适合双向通信
- 文件存储策略:本地磁盘(开发)→ 对象存储(生产)
课后实践
- 实现文件上传接口,限制最大 5MB + 只允许图片类型
- 实现文件下载接口,使用
StreamableFile流式返回 - 实现一个 SSE 端点,每秒推送服务器时间
第十六课:WebSocket 实时通信
覆盖文档:WebSockets(Gateways, Exception Filters, Pipes, Guards, Interceptors, Adapters) 前置知识:第9课 文档页数:6 页 | 核心主题:4
课程内容
[基础] WebSocket 网关
@WebSocketGateway()装饰器:默认与 HTTP 共享端口@SubscribeMessage('events')订阅消息@MessageBody()提取消息数据,@ConnectedSocket()获取客户端引用@WebSocketServer()获取底层 Server 实例- 响应方式:返回值自动发送、
client.emit()主动推送、Observable 多次发送 - 生命周期钩子:
OnGatewayInit、OnGatewayConnection、OnGatewayDisconnect - 注册:将 Gateway 加入 Module 的
providers数组
[中阶] Socket.IO 与 ws 平台
- Socket.IO(默认):功能丰富 — 房间、命名空间、自动重连、二进制支持
- ws:轻量高性能,原生浏览器 WebSocket 兼容
- 适配器切换:
app.useWebSocketAdapter(new WsAdapter(app)) - 命名空间:
@WebSocketGateway({ namespace: 'chat' }) - 端口配置:
@WebSocketGateway(3001)监听独立端口 - Socket 选项透传:
@WebSocketGateway({ cors: { origin: '*' } })
[中阶] WebSocket 增强器
- Guard/Pipe/Interceptor/Filter 用法与 HTTP 完全一致
- 关键差异:异常改用
WsException(而非HttpException) WsException自动发送'exception'事件给客户端BaseWsExceptionFilter继承并自定义异常处理ValidationPipe需要自定义exceptionFactory抛出WsException
[高阶] 适配器与多实例部署
WebSocketAdapter接口:create(),bindClientConnect(),bindMessageHandlers(),close()- 继承
IoAdapter扩展功能 - Redis 适配器:
@socket.io/redis-adapter— 多实例部署时通过 Redis 同步消息 - 负载均衡注意:Socket.IO 需要 sticky sessions 或禁用 polling
[资深] 源码:WebSocket 模块
packages/websockets/:WebSocket 模块核心@SubscribeMessage装饰器如何注册消息处理器- Gateway 的实例化和连接管理
- WebSocketAdapter 的抽象层设计
[架构] 实时通信架构
- WebSocket 应用场景:聊天、实时通知、协作编辑、游戏、仪表盘
- 连接管理:心跳检测、断线重连、连接池大小
- 水平扩展方案:Redis Pub/Sub 广播、专用 WebSocket 集群
- WebSocket vs SSE vs Long Polling 选型
课后实践
- 实现聊天室网关:
@SubscribeMessage('message')广播消息给所有连接 - 添加
AuthGuard保护 WebSocket 连接(验证 handshake 中的 token) - 实现
WsExceptionFilter自定义错误格式
第十七课:微服务架构
覆盖文档:Microservices(Overview, Redis, MQTT, NATS, RabbitMQ, Kafka, gRPC, Custom Transport, Exception Filters, Pipes, Guards, Interceptors), Hybrid Application(FAQ) 前置知识:第16课 文档页数:13 页 | 核心主题:5
课程内容
[基础] 微服务入门
- 微服务 vs HTTP:不走 HTTP 协议,使用消息传递
- 两种消息模式:
- 请求-响应(
@MessagePattern('sum')):client.send()返回 Observable,等待响应 - 事件(
@EventPattern('user_created')):client.emit()发射即忘
- 请求-响应(
- TCP 传输(最简入门):
- Server:
NestFactory.createMicroservice(AppModule, { transport: Transport.TCP, options: { port: 3001 } }) - Client:
ClientsModule.register([{ name: 'MATH_SERVICE', transport: Transport.TCP }]) @Inject('MATH_SERVICE') client: ClientProxy
- Server:
@Payload()和@Ctx()装饰器获取消息数据和上下文ClientProxy的status流和connect()方法
[中阶] 7 种传输层
| 传输层 | 包 | 特点 | 适用场景 |
|---|---|---|---|
| TCP | 内置 | 最简单,无外部依赖 | 本地/内网微服务通信 |
| Redis | ioredis | Pub/Sub,轻量,消息不持久化 | 简单事件分发 |
| NATS | nats | 高性能,分布式队列,queue 负载均衡 | 高吞吐消息传递 |
| MQTT | mqtt | IoT 协议,3 级 QoS,Topic 通配符 | 物联网设备通信 |
| RabbitMQ | amqplib | 消息确认(ACK),持久化,交换机类型 | 可靠消息传递 |
| Kafka | kafkajs | 流处理,分区,持久化,消费者组 | 大规模数据流 |
| gRPC | @grpc/grpc-js | Protocol Buffers,强类型,流式调用 | 高性能内部 RPC |
- 各传输层特有 Context:
RedisContext.getChannel()、KafkaContext.getTopic()、RmqContext.getMessage()等 - Record Builder:
NatsRecordBuilder、MqttRecordBuilder、RmqRecordBuilder、KafkaRecordBuilder
[高阶] 混合应用与自定义传输
- 混合应用:
app.connectMicroservice<MicroserviceOptions>({...})+app.startAllMicroservices()- 一个应用同时监听 HTTP + 微服务
inheritAppConfig: true:全局 Guard/Pipe/Interceptor 共享
- 微服务增强器:Pipes/Guards/Interceptors/Filters 用法与 HTTP 一致,异常改用
RpcException - 自定义传输策略:
- Server:继承
Server,实现CustomTransportStrategy(listen(),close()) - Client:继承
ClientProxy(publish(),dispatchEvent(),connect(),close())
- Server:继承
- gRPC 特性:
.proto文件定义服务,@GrpcMethod()、@GrpcStreamMethod()、@GrpcStreamCall() - Kafka 特性:消费者组、手动 offset 提交、心跳机制、
KafkaRetriableException
[资深] 源码:微服务抽象
packages/microservices/server/server.ts:Server 基类,messageHandlersMap 存储消息处理器packages/microservices/client/client-proxy.ts:ClientProxy 基类,send()和emit()的实现packages/microservices/server/server-tcp.ts:TCP 传输的完整实现(最适合入门阅读)ReadPacket<T>/WritePacket<T>:消息协议数据结构- 传输层的策略模式:所有传输共享同一套
@MessagePattern/@EventPattern接口
[架构] 分布式系统设计
- 微服务拆分原则:按业务域,每个服务有独立数据存储
- 通信模式选择:同步 RPC(gRPC/TCP)vs 异步消息(Kafka/RabbitMQ/NATS)
- 数据一致性:最终一致性 vs 强一致性,Saga 模式
- 服务发现与负载均衡
- 传输层选型决策树:
- 需要强类型 + 高性能 → gRPC
- 需要可靠投递 + 消息确认 → RabbitMQ
- 需要大规模事件流 → Kafka
- 简单事件广播 → Redis/NATS
课后实践
- 创建两个微服务(TCP):计算服务 + API 网关,网关转发请求到计算服务
- 将 TCP 传输切换为 Redis Pub/Sub,观察代码变化量(几乎为零)
- 创建混合应用:同时监听 HTTP 3000 端口 + TCP 3001 端口
第十八课:GraphQL — 类型安全的 API
覆盖文档:GraphQL(Quick Start, Resolvers, Mutations, Subscriptions, Scalars, Directives, Interfaces, Unions/Enums, Field Middleware, Mapped Types, Plugins, Complexity, Extensions, CLI Plugin, Generating SDL, Sharing Models, Other Features, Federation) 前置知识:第9课 文档页数:18 页 | 核心主题:6
课程内容
[基础] GraphQL 入门
- Code First vs Schema First:
- Code First:TypeScript 类 + 装饰器 → 自动生成 SDL(推荐)
- Schema First:先写
.graphql文件 →GraphQLDefinitionsFactory生成 TypeScript 类型
- Apollo vs Mercurius:
@nestjs/apollo(主流) vs@nestjs/mercurius(Fastify 原生) - 配置:
GraphQLModule.forRoot<ApolloDriverConfig>(ApolloDriver, { autoSchemaFile: true }) - 类型定义:
@ObjectType()+@Field(() => Int)定义 GraphQL 类型 - 解析器:
@Resolver(() => Cat)+@Query()+@Mutation()+@ResolveField() @Args()提取参数,@InputType()定义输入类型
[中阶] 类型系统
- 标量类型:内置
GraphQLISODateTime/GraphQLTimestamp;@Scalar()自定义(parseValue/serialize/parseLiteral) - 接口:
@InterfaceType()+resolveType动态类型判断 - 联合类型:
createUnionType({ name, types: () => [Cat, Dog] as const }) - 枚举:
registerEnumType(Role, { name: 'Role' }) - 映射类型:
PartialType(),PickType(),OmitType(),IntersectionType()
[中阶] 订阅与中间件
- Subscriptions:
PubSub+@Subscription()+asyncIterableIterator- 通过
graphql-ws配置(Apollo 推荐) filter函数筛选推送目标resolve函数修改推送数据- 生产环境使用外部 PubSub(Redis)
- 通过
- 字段中间件:
@Field({ middleware: [loggerMiddleware] })— 字段级前后逻辑 - 指令:
@Directive('@upper')+mapSchematransformer +transformSchema选项 - GraphQL 中的 Guard/Interceptor/Filter:
GqlExecutionContext.create(context)获取 GraphQL 上下文
[高阶] 高级特性
- 查询复杂度限制:
graphql-query-complexity+ComplexityPlugin防止恶意深查询 - Extensions:
@Extensions({ role: Role.ADMIN })字段级元数据 + 字段中间件权限检查 - Plugins:
@Plugin()实现ApolloServerPlugin— 请求生命周期钩子 - CLI Plugin:
nest-cli.json配置后编译时自动添加@Field(),减少 80% 样板代码 - 前后端模型共享:webpack alias 指向
@nestjs/graphql/dist/extra/graphql-model-shim - SDL 生成:
GraphQLSchemaBuilderModule+GraphQLSchemaFactory离线生成 schema
[高阶] Federation 微服务联邦
- Apollo Federation:拆分为多个 Subgraph 服务 + Gateway 聚合
ApolloFederationDriver:Subgraph 配置@Directive('@key(fields: "id")')标记实体主键@ResolveReference()实现跨服务实体解析- Gateway:
ApolloGatewayDriver+IntrospectAndCompose服务发现 - 限制:Federation 不支持 Subscriptions
[资深] 源码:GraphQL 模块
@nestjs/graphql的forRoot()动态模块实现- Resolver 是如何被
DiscoveryService发现并注册的 GraphQLSchemaHost提供运行时 schema 访问
[架构] GraphQL 架构策略
- REST vs GraphQL:REST 适合简单 CRUD + 开放 API,GraphQL 适合前端灵活查询 + BFF 层
- Schema 设计原则:以客户端需求为导向,避免过度暴露内部数据模型
- N+1 问题:DataLoader 批量加载
- Federation vs Schema Stitching:Federation 是官方推荐的微服务方案
课后实践
- 为 CatsModule 实现 GraphQL Code First 版本(Query + Mutation)
- 实现 Subscription:新增 Cat 时实时推送
- 添加
ComplexityPlugin限制查询深度
第十九课:API 文档与测试 — 质量保障
覆盖文档:OpenAPI(8页全部), Testing(Fundamentals), Recipes(REPL, CRUD Generator, Suites, Compodoc) 前置知识:第9课 文档页数:10 页 | 核心主题:5
课程内容
[基础] OpenAPI / Swagger
@nestjs/swagger:基于装饰器自动生成 API 文档DocumentBuilder:.setTitle(),.setDescription(),.setVersion(),.addBearerAuth(),.build()SwaggerModule.createDocument(app, config)+SwaggerModule.setup('api', app, document)@ApiProperty()标注 DTO 属性@ApiTags('cats')标注控制器分组- 25+ 响应装饰器:
@ApiOkResponse(),@ApiCreatedResponse(),@ApiForbiddenResponse() - 自动生成 JSON/YAML 端点:
/api-json,/api-yaml
[中阶] OpenAPI 进阶
- CLI Plugin 自动推断:
nest-cli.json配置后自动为 DTO 属性添加@ApiProperty - 安全方案:
@ApiBearerAuth()/@ApiOAuth2()/@ApiCookieAuth()+DocumentBuilder.addBearerAuth() - 映射类型:
PartialType,PickType,OmitType(从@nestjs/swagger导入以保留 API 元数据) - 多 Spec 端点:通过
include选项为不同模块生成独立文档 - 文件上传文档:
@ApiConsumes('multipart/form-data')+@ApiBody() - Schema 组合:
oneOf,anyOf,allOf+getSchemaPath() - 全局参数/响应:
DocumentBuilder.addGlobalParameters(),addGlobalResponse()
[基础] 单元测试
@nestjs/testing:Test.createTestingModule({ providers: [CatsService] }).compile().get(CatsService)获取待测实例.overrideProvider(CatsRepository).useValue(mockRepo)mock 依赖useMocker()自动 mock 所有未注册依赖- Jest 集成:
jest.fn(),jest.spyOn(),expect().toHaveBeenCalledWith()
[中阶] E2E 测试与高级 Mock
- E2E 测试:
module.createNestApplication()创建完整应用 supertest发送 HTTP 请求:request(app.getHttpServer()).get('/cats').expect(200).overrideGuard(AuthGuard).useValue({ canActivate: () => true }):跳过认证.overrideModule(ConfigModule).useModule(TestConfigModule):替换整个模块- Suites(Automock):
TestBed.solitary(CatsService)自动生成类型安全 mock - REPL 模式:
npm run start -- --entryFile repl,get(CatsService)交互式调试
[高阶] 测试进阶
- Request-scoped provider 测试:
ContextIdFactory.getByRequest控制 DI 子树 - 微服务测试:
module.createNestMicroservice() - 全局 Guard 测试:
APP_GUARD使用useExisting使 Guard 可被 override setLogger()自定义测试日志- Compodoc:
npx @compodoc/compodoc -p tsconfig.json -s生成项目文档 - CRUD Generator:
nest g resource cats一键生成完整 CRUD + 测试骨架
[资深] 源码:测试模块
packages/testing/testing-module.builder.ts:TestingModuleBuilder的 override 链实现packages/testing/testing-module.ts:TestingModule扩展了NestApplicationContextuseMocker如何通过 DI 元数据自动生成 mock
[架构] 质量保障策略
- API 文档即合约:Swagger/OpenAPI 作为前后端协作的 Single Source of Truth
- 测试金字塔:单元测试(70%)→ 集成测试(20%)→ E2E 测试(10%)
- 测试覆盖率目标:80%+ 代码覆盖率
- 契约测试:确保微服务接口兼容性
课后实践
- 为 REST API 添加完整 Swagger 文档,确保所有端点、DTO、响应都有文档
- 为 CatsService 编写单元测试(mock Repository),覆盖 CRUD + 异常路径
- 编写一个 E2E 测试覆盖完整认证 + CRUD 流程
第二十课:生产部署与架构设计
覆盖文档:Deployment, Performance(Fastify), Health Checks, Serverless, HTTPS, Keep-Alive, Common Errors, DevTools, CQRS, Async Local Storage, Nest Commander, SWC/Hot Reload, Sentry 前置知识:全部前序课程 文档页数:15+ 页 | 核心主题:6
课程内容
[基础] 构建与部署基础
- 构建:
npm run build→dist/main.js - 运行:
NODE_ENV=production node dist/main.js - Dockerfile 编写(多阶段构建):
FROM node:20 AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build FROM node:20-slim WORKDIR /app COPY --from=builder /app/dist ./dist COPY --from=builder /app/node_modules ./node_modules EXPOSE 3000 CMD ["node", "dist/main"] .dockerignore:排除node_modules、.git、dist- 健康检查:
@nestjs/terminusTerminusModule、HealthCheckService、@HealthCheck()装饰器- 内置指标:
HttpHealthIndicator、TypeOrmHealthIndicator、DiskHealthIndicator、MemoryHealthIndicator - 自定义 HealthIndicator:
HealthIndicatorService
[中阶] 生产最佳实践
- 环境变量:不硬编码,使用
ConfigService - 日志:JSON 格式 + 关联 ID(Correlation ID)
forceCloseConnections: true:优雅关闭时不等待 Keep-Alive 连接- HTTPS:
NestFactory.create(AppModule, { httpsOptions: { key, cert } }) - 多服务器:同时监听 HTTP(重定向)+ HTTPS
- 全局路径前缀:
app.setGlobalPrefix('api', { exclude: ['health'] }) - Raw Body:
{ rawBody: true }用于 Webhook 签名验证 - 性能:SWC 编译(20x 加速),Fastify 平台(2x 吞吐)
- 错误追踪:
@sentry/nestjs—SentryModule.forRoot()+SentryGlobalFilter
[中阶] 扩展与运维
- 垂直扩展(Scale Up):增加单服务器资源
- 水平扩展(Scale Out):多实例 + 负载均衡(Nginx / AWS ELB)
- Docker Compose 编排多服务
- CI/CD 流水线:构建 → 测试 → 镜像推送 → 部署
[高阶] Serverless 与特殊场景
- Serverless 部署(AWS Lambda):
@codegenie/serverless-express适配- 冷启动优化:
LazyModuleLoader按需加载模块
- CLI 应用:
nest-commander—CommandRunner+@Command()+@Option() - AsyncLocalStorage(
nestjs-cls):替代 Request-scoped provider,无 Scope 冒泡开销 - REPL 调试:运行时交互式探索 DI 容器
- 常见错误排查:
- "Cannot resolve dependency":检查
providers数组、forwardRef、NEST_DEBUG=true - 循环文件导入:避免 barrel file(index.ts)
- "Cannot resolve dependency":检查
[资深] 性能调优与 DevTools
- SWC vs tsc:SWC 是 Rust 编译器,不做类型检查,需配合
--type-check - Fastify 适配器源码:
packages/platform-fastify/adapters/fastify-adapter.ts - 请求管线性能分析:每层增强器的开销测量
- NestJS DevTools:依赖图可视化、路由导航、交互式 Playground、CI/CD 集成
[架构] 系统架构设计
-
单体到微服务的演进路径:
阶段1:NestJS 单体应用(模块化设计) ↓ 流量增长,团队扩大 阶段2:NestJS 混合应用(HTTP + 内部微服务) ↓ 独立部署需求 阶段3:NestJS 微服务集群(独立部署 + 消息总线) ↓ 前端查询复杂度增加 阶段4:API Gateway + GraphQL Federation + 微服务 -
CQRS 架构(
@nestjs/cqrs):- Command(写操作)→ CommandBus → CommandHandler → EventBus → EventHandler
- Query(读操作)→ QueryBus → QueryHandler
- Saga:
@Saga()监听事件流,触发后续命令 AggregateRoot:事件溯源基类
-
NestJS 技术栈全景图:
┌─────────────────────────────────────────────────────┐ │ 客户端 │ │ Web App / Mobile App / 第三方服务 │ └─────────────────┬───────────────────────────────────┘ │ ┌─────────────────┴───────────────────────────────────┐ │ API Gateway / BFF │ │ NestJS + GraphQL Federation / REST + Swagger │ │ 认证(JWT) + 限流(Throttler) + CORS + Helmet │ └──────┬──────────┬──────────┬────────────────────────┘ │ │ │ ┌──────┴───┐ ┌────┴────┐ ┌──┴────────┐ │ 用户服务 │ │ 订单服务 │ │ 支付服务 │ │ NestJS │ │ NestJS │ │ NestJS │ │ TypeORM │ │ Prisma │ │ Mongoose │ │ PostgreSQL│ │ MySQL │ │ MongoDB │ └──────┬───┘ └────┬────┘ └──┬────────┘ │ │ │ ┌──────┴──────────┴──────────┴────────────────────────┐ │ 消息总线 │ │ RabbitMQ / Kafka / NATS / Redis │ └─────────────────────────────────────────────────────┘ │ ┌──────┴──────────────────────────────────────────────┐ │ 基础设施 │ │ Redis(缓存) + BullMQ(队列) + Cron(定时) │ │ Sentry(监控) + ELK(日志) + Prometheus(指标) │ │ Docker + K8s + CI/CD │ └─────────────────────────────────────────────────────┘ -
技术决策清单:
决策点 推荐方案 备选方案 HTTP 引擎 Express(生态) Fastify(性能) ORM Prisma(新项目) TypeORM(成熟项目) 认证 @nestjs/jwt Passport(多策略) 缓存 Redis + cache-manager 内存缓存(单实例) 队列 BullMQ RabbitMQ / Kafka API 风格 REST + Swagger GraphQL(复杂前端) 微服务通信 gRPC(内部 RPC) NATS / Kafka(事件) 部署 Docker + K8s Serverless(低流量)
课后实践
- 为应用编写 Dockerfile(多阶段构建),用
docker-compose.yml编排应用 + 数据库 + Redis - 添加
@nestjs/terminus健康检查端点 - 实现优雅关闭:
enableShutdownHooks()+ 数据库连接清理 - 将应用从 Express 切换为 Fastify,验证所有功能正常
附录 A:知识点与课程映射表
| 文档章节 | 覆盖课程 |
|---|---|
| Introduction, First Steps | 第1课 |
| Controllers | 第2课 |
| Providers | 第3课 |
| Modules | 第4课 |
| Middleware | 第5课 |
| Exception Filters | 第5课 |
| Pipes, Validation | 第6课 |
| Guards | 第7课 |
| Interceptors | 第7课 |
| Custom Decorators | 第8课 |
| Custom Providers, Async Providers | 第3课 + 第9课 |
| Dynamic Modules | 第4课 |
| Injection Scopes | 第9课 |
| Circular Dependency | 第9课 |
| Module Reference | 第9课 |
| Lazy-loading Modules | 第4课 + 第20课 |
| Execution Context | 第7课 + 第8课 |
| Lifecycle Events | 第9课 |
| Discovery Service | 第8课 |
| Platform Agnosticism | 第1课 + 第9课 |
| Testing | 第19课 |
| Configuration | 第13课 |
| Database / MongoDB | 第10课 |
| Serialization | 第10课 |
| Versioning | 第2课 |
| Caching | 第14课 |
| Task Scheduling | 第14课 |
| Queues | 第14课 |
| Logger | 第13课 |
| Cookies / Session | 第13课 |
| Events | 第13课 |
| Compression | 第15课 |
| File Upload / Streaming | 第15课 |
| HTTP Module | 第15课 |
| MVC / Serve Static | 第15课 |
| Performance (Fastify) | 第20课 |
| Server-Sent Events | 第15课 |
| Authentication | 第11课 |
| Authorization | 第11课 |
| Encryption and Hashing | 第12课 |
| Helmet / CORS / CSRF | 第12课 |
| Rate Limiting | 第12课 |
| GraphQL(18 页) | 第18课 |
| WebSockets(6 页) | 第16课 |
| Microservices(12 页) | 第17课 |
| CLI(5 页) | 第1课 + 第4课 |
| OpenAPI(8 页) | 第19课 |
| REPL | 第19课 |
| CRUD Generator | 第2课 + 第19课 |
| SWC / Hot Reload | 第1课 + 第20课 |
| Passport | 第11课 |
| ORM Recipes | 第10课 |
| Health Checks | 第20课 |
| CQRS | 第20课 |
| Sentry | 第20课 |
| Nest Commander | 第20课 |
| Async Local Storage | 第20课 |
| Serverless | 第20课 |
| HTTP Adapter | 第1课 |
| Keep-Alive / Global Prefix / Raw Body | 第20课 |
| Hybrid Application | 第17课 |
| HTTPS & Multiple Servers | 第20课 |
| Request Lifecycle | 第5课 + 第7课 |
| Common Errors | 第20课 |
| Deployment | 第20课 |
| DevTools | 第20课 |
附录 B:各课程适合的用户收获速查
| 课程 | 基础用户收获 | 中阶用户收获 | 高阶用户收获 | 资深用户收获 | 架构用户收获 |
|---|---|---|---|---|---|
| 第1课 | 能创建并运行项目 | 掌握工程化配置 | 理解多平台抽象 | 读懂 NestFactory 源码 | 完成技术选型评估 |
| 第2课 | 能写 CRUD 路由 | 掌握高级路由技巧 | 实现 API 版本控制 | 读懂路由注册源码 | 设计 RESTful API 规范 |
| 第3课 | 能用 Service 注入 | 掌握 4 种 Provider 模式 | 异步/条件 Provider | 读懂 DI 容器源码 | IoC/DI 设计模式决策 |
| 第4课 | 能组织功能模块 | 模块共享与重导出 | 动态模块 forRoot | 读懂模块扫描源码 | 模块化架构设计 |
| 第5课 | 能用中间件和抛异常 | 自定义异常过滤器 | 平台无关异常处理 | 读懂异常处理源码 | 错误处理策略设计 |
| 第6课 | 能用内置管道验证 | class-validator/Zod | 自定义转换管道 | 读懂管道执行源码 | 验证策略选型 |
| 第7课 | 能用 Guard 做鉴权 | 角色守卫 + 拦截器 | ExecutionContext 深入 | 读懂管线组装源码 | 横切关注点设计 |
| 第8课 | 能写自定义装饰器 | 装饰器组合 | Discovery Service | 读懂元数据系统源码 | 元数据驱动架构 |
| 第9课 | 理解 3 种 Scope | 生命周期钩子 | ModuleRef + forwardRef | 读懂作用域源码 | 多租户架构设计 |
| 第10课 | 能接入 TypeORM | Mongoose/Prisma | 多数据库/事务/序列化 | Repository 源码模式 | 数据层架构选型 |
| 第11课 | 能实现 JWT 认证 | Passport + RBAC | CASL 细粒度权限 | 认证模块源码 | 认证架构设计 |
| 第12课 | 能配置 Helmet+CORS | CSRF + 限流 | 加密与哈希原理 | Node.js crypto 深入 | 安全架构设计 |
| 第13课 | 能用配置和日志 | 自定义 Logger + 事件 | Session + Cookie | ConfigModule 源码 | 基础设施架构 |
| 第14课 | 能用缓存 | 定时任务 + 队列 | 队列进阶 + Flow | 调度/队列源码 | 异步处理架构 |
| 第15课 | 能上传文件 | HTTP 客户端 + SSE | MVC + 静态文件 | StreamableFile 源码 | 文件与通信策略 |
| 第16课 | 能写 WS 网关 | Socket.IO 进阶 | 自定义适配器 | WS 模块源码 | 实时通信架构 |
| 第17课 | TCP 微服务通信 | 7 种传输层 | 自定义传输 + 混合应用 | 微服务抽象源码 | 分布式系统设计 |
| 第18课 | GraphQL 入门 | 类型系统 + 订阅 | Federation + 复杂度 | GraphQL 模块源码 | GraphQL 架构策略 |
| 第19课 | Swagger 文档 | E2E 测试 | 高级 Mock + REPL | 测试模块源码 | 质量保障策略 |
| 第20课 | Docker 部署 | 生产最佳实践 | Serverless + CQRS | DevTools + 性能调优 | 系统架构全景图 |