覆盖文档:Deployment, Performance(Fastify), Health Checks, Serverless, HTTPS, Keep-Alive, Common Errors, DevTools, CQRS, Async Local Storage, Nest Commander, SWC, Sentry 前置知识:全部前序课程 源码重点:
packages/platform-fastify/adapters/fastify-adapter.ts,packages/core/nest-application.ts
一、构建与部署基础
[基础] 本节面向初学者,掌握 NestJS 应用的构建、容器化与健康检查。
1.1 构建与运行
# 1. 编译 TypeScript → JavaScript
npm run build
# 输出到 dist/ 目录
# 2. 以生产模式运行
NODE_ENV=production node dist/main.js
构建产物结构:
dist/
├── main.js # 应用入口
├── app.module.js # 根模块
├── app.controller.js # 控制器
├── app.service.js # 服务
└── ... # 其他编译后的文件
1.2 Docker 多阶段构建
多阶段构建将编译环境与运行环境分离,大幅减小镜像体积:
# ============ 阶段一:构建 ============
FROM node:20-alpine AS builder
WORKDIR /app
# 1. 先复制依赖文件(利用 Docker 层缓存)
COPY package*.json ./
RUN npm ci --only=production && \
cp -R node_modules prod_node_modules && \
npm ci
# 2. 复制源码并编译
COPY . .
RUN npm run build
# ============ 阶段二:运行 ============
FROM node:20-alpine AS runner
WORKDIR /app
# 3. 只复制运行所需文件
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/prod_node_modules ./node_modules
# 4. 安全:使用非 root 用户
RUN addgroup -g 1001 -S nodejs && \
adduser -S nestjs -u 1001
USER nestjs
EXPOSE 3000
# 5. 设置生产环境变量
ENV NODE_ENV=production
# 6. 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
CMD ["node", "dist/main.js"]
.dockerignore 文件:
node_modules
dist
.git
.github
*.md
.env*
test
coverage
1.3 健康检查 — @nestjs/terminus
健康检查是生产部署的必备组件,让负载均衡器和编排系统知道应用是否正常运行:
npm install --save @nestjs/terminus
// health/health.module.ts
import { Module } from '@nestjs/common';
import { TerminusModule } from '@nestjs/terminus';
import { HealthController } from './health.controller';
@Module({
imports: [TerminusModule],
controllers: [HealthController],
})
export class HealthModule {}
// health/health.controller.ts
import { Controller, Get } from '@nestjs/common';
import {
HealthCheckService,
HealthCheck,
HttpHealthIndicator,
TypeOrmHealthIndicator,
DiskHealthIndicator,
MemoryHealthIndicator,
} from '@nestjs/terminus';
@Controller('health')
export class HealthController {
constructor(
private readonly health: HealthCheckService,
private readonly http: HttpHealthIndicator,
private readonly db: TypeOrmHealthIndicator,
private readonly disk: DiskHealthIndicator,
private readonly memory: MemoryHealthIndicator,
) {}
@Get()
@HealthCheck()
check() {
return this.health.check([
// HTTP 外部依赖检查
() => this.http.pingCheck('api-docs', 'https://docs.nestjs.com'),
// 数据库连接检查
() => this.db.pingCheck('database'),
// 磁盘空间检查(阈值 90%)
() => this.disk.checkStorage('disk', {
path: '/',
thresholdPercent: 0.9,
}),
// 内存检查(阈值 300MB)
() => this.memory.checkHeap('memory_heap', 300 * 1024 * 1024),
// RSS 内存检查(阈值 500MB)
() => this.memory.checkRSS('memory_rss', 500 * 1024 * 1024),
]);
}
}
自定义健康指标:
import { Injectable } from '@nestjs/common';
import { HealthIndicatorService, HealthIndicatorResult } from '@nestjs/terminus';
@Injectable()
export class RedisHealthIndicator {
constructor(
private readonly healthIndicatorService: HealthIndicatorService,
private readonly redisService: RedisService,
) {}
async isHealthy(key: string): Promise<HealthIndicatorResult> {
const indicator = this.healthIndicatorService.check(key);
try {
await this.redisService.ping();
return indicator.up();
} catch (error) {
return indicator.down({ message: error.message });
}
}
}
内置健康指标速查:
| 指标 | 类 | 检查内容 |
|---|---|---|
| HTTP | HttpHealthIndicator | 外部 HTTP 服务可达性 |
| TypeORM | TypeOrmHealthIndicator | 数据库连接状态 |
| Mongoose | MongooseHealthIndicator | MongoDB 连接状态 |
| MikroORM | MikroOrmHealthIndicator | MikroORM 连接状态 |
| Prisma | PrismaHealthIndicator | Prisma 连接状态 |
| 磁盘 | DiskHealthIndicator | 磁盘空间使用率 |
| 内存 | MemoryHealthIndicator | 堆内存 / RSS 使用量 |
二、生产最佳实践
[中阶] 本节面向有经验的开发者,掌握生产环境配置要点。
2.1 环境变量与配置
生产环境绝不硬编码配置,使用 ConfigService 管理:
// main.ts
import { ConfigService } from '@nestjs/config';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const configService = app.get(ConfigService);
const port = configService.get<number>('PORT', 3000);
const host = configService.get<string>('HOST', '0.0.0.0');
await app.listen(port, host);
}
2.2 JSON 日志与 Correlation ID
生产环境使用结构化 JSON 日志,便于 ELK/Datadog 等系统收集和分析:
import { NestFactory } from '@nestjs/core';
import { ConsoleLogger } from '@nestjs/common';
async function bootstrap() {
const app = await NestFactory.create(AppModule, {
// JSON 格式日志输出
logger: new ConsoleLogger({
json: true,
colors: false, // 生产环境不需要颜色
}),
});
await app.listen(3000);
}
Correlation ID 中间件贯穿请求全链路:
import { Injectable, NestMiddleware } from '@nestjs/common';
import { randomUUID } from 'crypto';
@Injectable()
export class CorrelationIdMiddleware implements NestMiddleware {
use(req: any, res: any, next: () => void) {
const correlationId = req.headers['x-correlation-id'] || randomUUID();
req.correlationId = correlationId;
res.setHeader('x-correlation-id', correlationId);
next();
}
}
2.3 优雅关闭
async function bootstrap() {
const app = await NestFactory.create(AppModule, {
// 优雅关闭时不等待 Keep-Alive 连接超时
forceCloseConnections: true,
});
// 启用关闭钩子(监听 SIGTERM、SIGINT)
app.enableShutdownHooks();
await app.listen(3000);
}
2.4 HTTPS 配置
import { readFileSync } from 'fs';
async function bootstrap() {
const httpsOptions = {
key: readFileSync('./secrets/private-key.pem'),
cert: readFileSync('./secrets/certificate.pem'),
};
const app = await NestFactory.create(AppModule, { httpsOptions });
await app.listen(443);
}
同时运行 HTTP 重定向 + HTTPS 服务器:
import { NestFactory } from '@nestjs/core';
import * as express from 'express';
import * as http from 'http';
async function bootstrap() {
// 1. 创建 HTTPS 应用
const app = await NestFactory.create(AppModule, { httpsOptions });
await app.listen(443);
// 2. 创建 HTTP 重定向服务器
const httpApp = express();
httpApp.get('*', (req, res) => {
res.redirect(301, `https://${req.headers.host}${req.url}`);
});
http.createServer(httpApp).listen(80);
}
2.5 全局前缀与排除
app.setGlobalPrefix('api', {
exclude: [
'health', // 健康检查不加前缀
{ path: 'metrics', method: RequestMethod.GET }, // 指标端点
],
});
// 结果:GET /api/cats, GET /api/users, GET /health, GET /metrics
2.6 Raw Body — Webhook 签名验证
const app = await NestFactory.create(AppModule, {
rawBody: true, // 启用原始请求体
});
// 在 Controller 中获取原始 body
@Post('webhook')
handleWebhook(@RawBody() rawBody: Buffer, @Headers('x-signature') signature: string) {
// 使用 rawBody 验证签名
const isValid = verifySignature(rawBody, signature);
if (!isValid) {
throw new UnauthorizedException('Invalid webhook signature');
}
}
2.7 SWC 加速编译 + Fastify 提升吞吐
# SWC 编译(约 20 倍于 tsc)
npm install --save-dev @swc/cli @swc/core
nest start -b swc --watch
# Fastify 平台(约 2 倍于 Express 吞吐)
npm install --save @nestjs/platform-fastify
import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify';
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter(),
);
await app.listen(3000, '0.0.0.0');
| 优化手段 | 效果 | 适用阶段 |
|---|---|---|
| SWC | ~20x 编译加速 | 开发 + 构建 |
| Fastify | ~2x 吞吐提升 | 运行时 |
| forceCloseConnections | 快速关闭 | 部署重启 |
2.8 Sentry 错误追踪
npm install --save @sentry/nestjs @sentry/profiling-node
// instrument.ts — 必须在应用启动前加载
import * as Sentry from '@sentry/nestjs';
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 1.0,
});
// app.module.ts
import { SentryModule } from '@sentry/nestjs/setup';
@Module({
imports: [
SentryModule.forRoot(), // 注册 Sentry 模块
// ... 其他模块
],
})
export class AppModule {}
// main.ts
import { SentryGlobalFilter } from '@sentry/nestjs/setup';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 全局异常过滤器 — 自动上报未捕获异常到 Sentry
const { httpAdapter } = app.get(HttpAdapterHost);
app.useGlobalFilters(new SentryGlobalFilter(httpAdapter));
await app.listen(3000);
}
三、扩展与运维
[中阶] 本节面向有经验的开发者,掌握应用的扩展策略。
3.1 扩展策略
┌─────────────────────────────────────────────────────┐
│ 扩展方式 │
│ │
│ 垂直扩展(Scale Up) 水平扩展(Scale Out) │
│ ┌──────────┐ ┌──────────────────┐ │
│ │ 更多 CPU │ │ 实例1 实例2 实例3 │ │
│ │ 更多 RAM │ │ ↑ ↑ ↑ │ │
│ │ 更快磁盘 │ │ └──────┼──────┘ │ │
│ │ 单台服务器 │ │ 负载均衡器 │ │
│ └──────────┘ └──────────────────┘ │
│ │
│ 适用:快速解决,小规模 适用:大规模,高可用 │
│ 限制:单机上限 注意:无状态设计 │
└─────────────────────────────────────────────────────┘
水平扩展的前提:应用必须无状态:
- Session 存储在 Redis,不存在内存
- 文件上传到对象存储(S3/OSS),不存在本地
- 缓存使用 Redis,不使用进程内存
- WebSocket 使用 Redis Adapter 同步
3.2 Docker Compose 编排
# docker-compose.yml
version: '3.8'
services:
api:
build: .
ports:
- '3000:3000'
environment:
- NODE_ENV=production
- DATABASE_HOST=postgres
- REDIS_HOST=redis
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
restart: unless-stopped
healthcheck:
test: ['CMD', 'wget', '--spider', '-q', 'http://localhost:3000/health']
interval: 30s
timeout: 5s
retries: 3
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: nestapp
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASS}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U ${DB_USER}']
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
healthcheck:
test: ['CMD', 'redis-cli', 'ping']
interval: 10s
timeout: 5s
retries: 5
volumes:
postgres_data:
redis_data:
3.3 CI/CD 流水线
┌─────────┐ ┌─────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Git │ → │ Lint │ → │ Test │ → │ Build │ → │ Deploy │
│ Push │ │ + Type │ │ + Cover │ │ Docker │ │ K8s / │
│ │ │ Check │ │ 80%+ │ │ Image │ │ ECS │
└─────────┘ └─────────┘ └──────────┘ └──────────┘ └──────────┘
↓ fail
阻止合并
关键步骤:
- Lint + 类型检查:
eslint+tsc --noEmit - 测试 + 覆盖率:
jest --coverage,阈值 80% - 构建 Docker 镜像:多阶段构建
- 推送镜像:到私有仓库
- 部署:滚动更新(zero-downtime)
四、Serverless 与特殊场景
[高阶] 本节面向深入使用者,掌握 Serverless 部署、CLI 应用和常见错误排查。
4.1 AWS Lambda — Serverless 部署
npm install --save @codegenie/serverless-express
// lambda.ts
import { NestFactory } from '@nestjs/core';
import { ExpressAdapter } from '@nestjs/platform-express';
import serverlessExpress from '@codegenie/serverless-express';
import { Callback, Context, Handler } from 'aws-lambda';
import * as express from 'express';
import { AppModule } from './app.module';
let server: Handler;
async function bootstrap(): Promise<Handler> {
const expressApp = express();
const nestApp = await NestFactory.create(
AppModule,
new ExpressAdapter(expressApp),
);
await nestApp.init();
return serverlessExpress({ app: expressApp });
}
export const handler: Handler = async (
event: any,
context: Context,
callback: Callback,
) => {
// 复用实例,减少冷启动
server = server ?? (await bootstrap());
return server(event, context, callback);
};
冷启动优化 — LazyModuleLoader:
import { LazyModuleLoader } from '@nestjs/core';
@Injectable()
export class AppService {
constructor(private readonly lazyModuleLoader: LazyModuleLoader) {}
async processReport() {
// 按需加载重量级模块,减少冷启动时间
const { ReportModule } = await import('./report/report.module');
const moduleRef = await this.lazyModuleLoader.load(() => ReportModule);
const reportService = moduleRef.get(ReportService);
return reportService.generate();
}
}
4.2 Nest Commander — CLI 应用
npm install nest-commander
import { Command, CommandRunner, Option } from 'nest-commander';
@Command({
name: 'seed',
description: '初始化数据库种子数据',
})
export class SeedCommand extends CommandRunner {
constructor(private readonly seedService: SeedService) {
super();
}
async run(passedParams: string[], options?: Record<string, any>): Promise<void> {
const count = options?.count ?? 10;
console.log(`Seeding ${count} records...`);
await this.seedService.seed(count);
console.log('Seeding complete!');
}
@Option({
flags: '-c, --count <count>',
description: '生成的记录数量',
})
parseCount(val: string): number {
return parseInt(val, 10);
}
}
// main.ts(CLI 模式)
import { CommandFactory } from 'nest-commander';
import { AppModule } from './app.module';
async function bootstrap() {
await CommandFactory.run(AppModule, ['warn', 'error']);
}
bootstrap();
# 运行 CLI 命令
npx ts-node src/main.ts seed --count 100
4.3 AsyncLocalStorage — nestjs-cls
替代 Request-scoped Provider,无 Scope 冒泡开销:
npm install nestjs-cls
import { ClsModule, ClsService } from 'nestjs-cls';
@Module({
imports: [
ClsModule.forRoot({
global: true,
middleware: {
mount: true,
setup: (cls, req) => {
// 在请求开始时设置值
cls.set('userId', req.headers['x-user-id']);
cls.set('correlationId', req.headers['x-correlation-id'] || randomUUID());
},
},
}),
],
})
export class AppModule {}
// 在任何 Service 中获取请求上下文(无需 Scope.REQUEST)
@Injectable()
export class AuditService {
constructor(private readonly cls: ClsService) {}
log(action: string) {
const userId = this.cls.get('userId');
const correlationId = this.cls.get('correlationId');
console.log(`[${correlationId}] User ${userId}: ${action}`);
}
}
| 方案 | Scope 冒泡 | 性能影响 | 使用场景 |
|---|---|---|---|
Scope.REQUEST | 有(整条依赖链) | 高 | 简单场景 |
nestjs-cls | 无 | 极低 | 推荐方案 |
4.4 REPL 模式
运行时交互式探索 DI 容器,用于调试和快速验证:
// repl.ts
import { repl } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const replServer = await repl(AppModule);
replServer.setupHistory('.nestjs_repl_history', (err) => {
if (err) console.error(err);
});
}
bootstrap();
npm run start -- --entryFile repl
4.5 常见错误排查
"Cannot resolve dependency" 错误
Nest can't resolve dependencies of the CatsService (?).
Please make sure that the argument "CatsRepository" at index [0]
is available in the CatsModule context.
排查步骤:
// 1. 确认 Provider 在 providers 数组中
@Module({
providers: [CatsService, CatsRepository], // CatsRepository 不能遗漏
})
// 2. 如果依赖来自其他模块,确认已 import 且已 export
@Module({
imports: [DatabaseModule], // 需要 import
})
// 3. 循环依赖使用 forwardRef
@Injectable()
export class CatsService {
constructor(
@Inject(forwardRef(() => DogsService)) // 解决循环依赖
private readonly dogsService: DogsService,
) {}
}
// 4. 启用调试模式查看详细信息
// 设置环境变量
// NEST_DEBUG=true
避免 Barrel File 导致的虚假循环依赖
// 错误:从 barrel file 导入可能导致循环依赖
import { CatsService } from './'; // index.ts 重导出
// 正确:直接从文件导入
import { CatsService } from './cats.service';
五、性能调优与 DevTools
[资深] 本节面向希望深入理解框架内部机制的读者。
5.1 SWC vs tsc 对比
| 特性 | tsc | SWC |
|---|---|---|
| 语言 | TypeScript(自举) | Rust |
| 编译速度 | 基准 | ~20x 更快 |
| 类型检查 | 内置 | 不支持(需额外 --type-check) |
| 装饰器元数据 | 原生支持 | 支持(@swc/core v1.3+) |
| Swagger Plugin | 支持 | 不支持 |
| Watch 模式 | 支持 | 支持 |
// nest-cli.json — SWC 配置
{
"compilerOptions": {
"builder": "swc",
"typeCheck": true // 并行运行类型检查
}
}
5.2 Fastify 适配器源码
文件位置:packages/platform-fastify/adapters/fastify-adapter.ts
export class FastifyAdapter extends AbstractHttpAdapter {
// Fastify 实例
private readonly instance: FastifyInstance;
constructor(instanceOrOptions?: FastifyInstance | FastifyServerOptions) {
const instance = instanceOrOptions instanceof Object && 'server' in instanceOrOptions
? instanceOrOptions as FastifyInstance
: fastify(instanceOrOptions as FastifyServerOptions);
super(instance);
}
// 路由注册 — 映射 NestJS 装饰器到 Fastify 路由
public get(handler: RequestHandler);
public get(path: string, handler: RequestHandler);
public get(...args: any[]) {
return this.injectConstraintsIfVersioned('GET', ...args);
}
// 监听端口 — Fastify 默认只监听 localhost
public listen(port: number | string, hostname?: string): Promise<void> {
return this.instance.listen({
port: typeof port === 'string' ? parseInt(port, 10) : port,
host: hostname || '0.0.0.0',
});
}
}
核心设计:FastifyAdapter 继承 AbstractHttpAdapter,将 NestJS 的路由注册 API 映射到 Fastify 的路由系统。所有平台差异被封装在 Adapter 中,框架核心代码完全平台无关。
5.3 请求管线性能
请求到达 → Middleware → Guard → Interceptor(前) → Pipe → Handler → Interceptor(后) → Filter → 响应
(异常时)
每一层都有开销:
Middleware: ~0.01ms(Express/Fastify 原生)
Guard: ~0.05ms(含 Reflector 元数据读取)
Interceptor: ~0.05ms(RxJS Observable 创建)
Pipe: ~0.1-1ms(class-validator 验证最耗时)
Handler: 业务逻辑时间
优化建议:
1. 减少全局 Guard/Interceptor 数量
2. Pipe 验证使用白名单模式(whitelist: true)
3. 避免不必要的 class-transformer 序列化
4. 使用 Fastify 替代 Express(底层更快)
5.4 NestJS DevTools
NestJS DevTools 是官方提供的可视化调试工具:
npm install --save @nestjs/devtools-integration
import { DevtoolsModule } from '@nestjs/devtools-integration';
@Module({
imports: [
DevtoolsModule.register({
http: process.env.NODE_ENV !== 'production',
}),
],
})
export class AppModule {}
DevTools 提供的能力:
| 功能 | 说明 |
|---|---|
| 依赖图 | 可视化模块、Provider、Controller 的依赖关系 |
| 路由导航 | 查看所有注册路由及其元数据 |
| Playground | 交互式调用 Provider 方法 |
| 性能分析 | 请求管线各阶段耗时 |
| CI/CD 集成 | 在 CI 中生成依赖图快照,检测回归 |
六、系统架构设计
[架构] 本节面向技术负责人和架构师。
6.1 单体到微服务的演进路径
┌─────────────────────────────────────────────────────────────────┐
│ 阶段 1:NestJS 单体应用(模块化设计) │
│ │
│ ┌──────────────────────────────────────────┐ │
│ │ NestJS 单体 │ │
│ │ ┌────────┐ ┌────────┐ ┌────────────┐ │ │
│ │ │UsersModule│ │OrdersModule│ │PaymentModule│ │ │
│ │ └────────┘ └────────┘ └────────────┘ │ │
│ │ 共享数据库 │ │
│ └──────────────────────────────────────────┘ │
│ 适用:初创期,团队 < 5 人 │
│ │
│ ↓ 流量增长,团队扩大 │
│ │
│ 阶段 2:NestJS 混合应用(HTTP + 内部微服务) │
│ │
│ ┌────────────────┐ ┌──────────────────┐ │
│ │ NestJS HTTP │ TCP │ NestJS 微服务 │ │
│ │ API Gateway │ ───→ │ PaymentService │ │
│ │ (Users+Orders) │ │ (独立数据库) │ │
│ └────────────────┘ └──────────────────┘ │
│ 适用:渐进拆分,最小改动成本 │
│ │
│ ↓ 独立部署需求 │
│ │
│ 阶段 3:NestJS 微服务集群 │
│ │
│ ┌────────┐ ┌────────┐ ┌────────────┐ │
│ │ Users │ │ Orders │ │ Payment │ │
│ │ Service │ │ Service │ │ Service │ │
│ └───┬────┘ └───┬────┘ └─────┬──────┘ │
│ └───────────┼─────────────┘ │
│ 消息总线(NATS / RabbitMQ / Kafka) │
│ 适用:中大型团队,独立部署和扩展 │
│ │
│ ↓ 前端查询复杂度增加 │
│ │
│ 阶段 4:API Gateway + GraphQL Federation + 微服务 │
│ │
│ ┌──────────────────────────────────┐ │
│ │ GraphQL Gateway │ │
│ │ (Apollo Federation Router) │ │
│ └───┬──────────┬──────────┬────────┘ │
│ │ │ │ │
│ ┌───┴───┐ ┌──┴────┐ ┌─┴───────┐ │
│ │Users │ │Orders │ │Payment │ │
│ │Subgraph│ │Subgraph│ │Subgraph│ │
│ └───────┘ └───────┘ └────────┘ │
│ 适用:大型系统,前端灵活查询需求 │
└─────────────────────────────────────────────────────────────────┘
6.2 CQRS 架构
@nestjs/cqrs 实现命令查询职责分离:
npm install --save @nestjs/cqrs
┌─────────────────────────────────────────────────────────────┐
│ CQRS 架构 │
│ │
│ 写操作(Command) 读操作(Query) │
│ ┌────────────────────┐ ┌─────────────────────┐ │
│ │ CreateCatCommand │ │ GetCatsQuery │ │
│ │ ↓ │ │ ↓ │ │
│ │ CommandBus │ │ QueryBus │ │
│ │ ↓ │ │ ↓ │ │
│ │ CreateCatHandler │ │ GetCatsHandler │ │
│ │ ↓ │ │ ↓ │ │
│ │ 写入数据库 │ │ 读取数据库(可读副本) │ │
│ │ ↓ │ └─────────────────────┘ │
│ │ EventBus │ │
│ │ ↓ │ │
│ │ CatCreatedEvent │ │
│ │ ↓ │ │
│ │ EventHandler(s) │ │
│ │ (发邮件/更新缓存) │ │
│ └────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
实现示例:
// 1. 定义 Command
export class CreateCatCommand {
constructor(
public readonly name: string,
public readonly age: number,
public readonly breed: string,
) {}
}
// 2. 定义 Command Handler
@CommandHandler(CreateCatCommand)
export class CreateCatHandler implements ICommandHandler<CreateCatCommand> {
constructor(
private readonly repository: CatsRepository,
private readonly eventBus: EventBus,
) {}
async execute(command: CreateCatCommand) {
const cat = await this.repository.create(command);
// 发布领域事件
this.eventBus.publish(new CatCreatedEvent(cat.id, cat.name));
return cat;
}
}
// 3. 定义 Event
export class CatCreatedEvent {
constructor(
public readonly catId: number,
public readonly catName: string,
) {}
}
// 4. 定义 Event Handler
@EventsHandler(CatCreatedEvent)
export class CatCreatedHandler implements IEventHandler<CatCreatedEvent> {
handle(event: CatCreatedEvent) {
console.log(`Cat created: ${event.catName}`);
// 发送通知、更新缓存、同步搜索引擎等
}
}
// 5. 定义 Query
export class GetCatsQuery {
constructor(public readonly page: number, public readonly limit: number) {}
}
// 6. 定义 Query Handler
@QueryHandler(GetCatsQuery)
export class GetCatsHandler implements IQueryHandler<GetCatsQuery> {
constructor(private readonly repository: CatsRepository) {}
async execute(query: GetCatsQuery) {
return this.repository.findAll(query.page, query.limit);
}
}
// 7. Saga — 事件驱动的命令链
@Injectable()
export class CatsSaga {
@Saga()
catCreated = (events$: Observable<any>): Observable<ICommand> => {
return events$.pipe(
ofType(CatCreatedEvent),
map((event) => new SendWelcomeEmailCommand(event.catId)),
);
};
}
// 8. 在 Controller 中使用
@Controller('cats')
export class CatsController {
constructor(
private readonly commandBus: CommandBus,
private readonly queryBus: QueryBus,
) {}
@Post()
create(@Body() dto: CreateCatDto) {
return this.commandBus.execute(new CreateCatCommand(dto.name, dto.age, dto.breed));
}
@Get()
findAll(@Query('page') page: number, @Query('limit') limit: number) {
return this.queryBus.execute(new GetCatsQuery(page, limit));
}
}
// 9. 模块注册
@Module({
imports: [CqrsModule],
controllers: [CatsController],
providers: [
CreateCatHandler,
GetCatsHandler,
CatCreatedHandler,
CatsSaga,
CatsRepository,
],
})
export class CatsModule {}
6.3 NestJS 技术栈全景图
┌─────────────────────────────────────────────────────────────────┐
│ 客 户 端 │
│ Web App Mobile App 第三方服务 IoT 设备 │
└──────┬──────────────────┬───────────────┬──────────────┬────────┘
│ HTTP/HTTPS │ WebSocket │ gRPC │ MQTT
▼ ▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ API 网关 / BFF 层 │
│ │
│ NestJS Application │
│ ├── REST API + Swagger 文档(@nestjs/swagger) │
│ ├── GraphQL Federation Gateway(@nestjs/graphql + Apollo) │
│ ├── WebSocket Gateway(@nestjs/websockets + Socket.IO) │
│ │ │
│ ├── 安全层 │
│ │ ├── JWT 认证(@nestjs/jwt) │
│ │ ├── RBAC/CASL 授权 │
│ │ ├── Helmet + CORS + CSRF │
│ │ ├── 限流(@nestjs/throttler) │
│ │ └── 加密(crypto + bcrypt) │
│ │ │
│ └── 请求管线 │
│ Middleware → Guard → Interceptor → Pipe → Handler → Filter │
└──────┬──────────────────┬───────────────┬───────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ 用户服务 │ │ 订单服务 │ │ 支付服务 │
│ NestJS │ │ NestJS │ │ NestJS │
│ TypeORM │ │ Prisma │ │ Mongoose │
│ PostgreSQL │ │ MySQL │ │ MongoDB │
│ CQRS │ │ Event Driven │ │ Saga │
└──────┬───────┘ └──────┬───────┘ └──────┬──────┘
│ │ │
└─────────────────┼─────────────────┘
▼
┌─────────────────────────────────────────────────────────────────┐
│ 消息总线 │
│ │
│ RabbitMQ(可靠投递) Kafka(流处理) NATS(高吞吐) Redis(轻量) │
│ │
│ @MessagePattern('sum') ← 请求-响应模式 │
│ @EventPattern('user.created') ← 事件驱动模式 │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 基础设施层 │
│ │
│ ┌───────────┐ ┌───────────┐ ┌──────────┐ ┌──────────────────┐ │
│ │ Redis │ │ BullMQ │ │ Cron │ │ AsyncLocal │ │
│ │ 缓存 │ │ 消息队列 │ │ 定时任务 │ │ Storage(CLS) │ │
│ │ Session │ │ 延迟任务 │ │ @Cron() │ │ 请求上下文 │ │
│ └───────────┘ └───────────┘ └──────────┘ └──────────────────┘ │
│ │
│ ┌───────────┐ ┌───────────┐ ┌──────────┐ ┌──────────────────┐ │
│ │ Sentry │ │ ELK │ │Prometheus│ │ NestJS DevTools │ │
│ │ 错误追踪 │ │ 日志收集 │ │ 指标监控 │ │ 依赖图 + 调试 │ │
│ └───────────┘ └───────────┘ └──────────┘ └──────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ 部署:Docker + Kubernetes + CI/CD + Health Checks │ │
│ │ 或 Serverless:AWS Lambda + @codegenie/serverless-express │ │
│ └───────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
6.4 技术决策清单
| 决策点 | 推荐方案 | 备选方案 | 决策依据 |
|---|---|---|---|
| HTTP 引擎 | Express | Fastify | Express 生态丰富;Fastify 性能高 |
| ORM | Prisma | TypeORM / MikroORM | Prisma 类型安全最强;TypeORM 最成熟 |
| 认证 | @nestjs/jwt | Passport(多策略) | JWT 简单直接;Passport 支持 OAuth2 等 |
| 缓存 | Redis + cache-manager | 内存缓存 | 单实例用内存;多实例必须 Redis |
| 队列 | BullMQ + Redis | RabbitMQ / Kafka | BullMQ 简单;RabbitMQ 可靠;Kafka 大规模 |
| API 风格 | REST + Swagger | GraphQL | REST 通用;GraphQL 适合复杂前端查询 |
| 微服务通信 | gRPC(内部 RPC) | NATS / Kafka(事件) | gRPC 强类型高性能;NATS 简单高吞吐 |
| 部署方式 | Docker + K8s | Serverless | 容器化主流;Serverless 适合低流量 |
| 日志 | JSON + ELK | Datadog / Sentry | ELK 自建;Datadog/Sentry 托管 |
| 请求上下文 | nestjs-cls | Scope.REQUEST | CLS 无性能损耗;Scope 冒泡影响性能 |
七、课后实践
练习 1:Docker 部署(基础)
# 1. 编写 Dockerfile(多阶段构建)
# 2. 编写 .dockerignore
# 3. 编写 docker-compose.yml(应用 + PostgreSQL + Redis)
# 4. 构建并运行
docker-compose up --build
# 5. 验证 http://localhost:3000/health
练习 2:健康检查(基础)
// 1. 安装 @nestjs/terminus
// 2. 创建 HealthModule + HealthController
// 3. 添加 Database + Memory 健康指标
// 4. 创建自定义 RedisHealthIndicator
// 5. 验证 GET /health 返回正常
练习 3:优雅关闭与 Sentry(中阶)
// 1. 启用 enableShutdownHooks()
// 2. 实现 onModuleDestroy() 清理数据库连接
// 3. 配置 forceCloseConnections: true
// 4. 集成 Sentry 错误追踪
// 5. 主动抛出异常,验证 Sentry 收到报告
练习 4:CQRS 实践(高阶)
// 1. 安装 @nestjs/cqrs
// 2. 将 CatsService.create() 改为 CreateCatCommand + Handler
// 3. 将 CatsService.findAll() 改为 GetCatsQuery + Handler
// 4. 创建 CatCreatedEvent + Handler(打印日志)
// 5. 创建 Saga:猫创建后自动发送通知
练习 5:性能对比(资深)
# 1. 分别用 tsc 和 SWC 编译项目,对比编译时间
# 2. 分别用 Express 和 Fastify 启动,用 autocannon 压测
# npx autocannon -c 100 -d 10 http://localhost:3000/cats
# 3. 记录 RPS、延迟 P99,对比两个平台的差异
# 4. 阅读 FastifyAdapter 源码,理解平台抽象层设计
八、本课知识点总结
| 知识点 | 要点 |
|---|---|
| 构建 | npm run build → dist/main.js,NODE_ENV=production |
| Docker | 多阶段构建,非 root 用户,.dockerignore |
| 健康检查 | @nestjs/terminus,TerminusModule,内置 5 种指标,自定义 HealthIndicator |
| 环境变量 | ConfigService,不硬编码,运行时注入 |
| JSON 日志 | ConsoleLogger({ json: true }),Correlation ID 贯穿全链路 |
| 优雅关闭 | forceCloseConnections + enableShutdownHooks() |
| HTTPS | httpsOptions: { key, cert },HTTP 重定向 + HTTPS |
| 全局前缀 | setGlobalPrefix('api', { exclude: ['health'] }) |
| Raw Body | { rawBody: true } 用于 Webhook 签名验证 |
| SWC | ~20x 编译加速,不支持 Swagger Plugin |
| Fastify | ~2x 吞吐提升,需注意 0.0.0.0 监听 |
| Sentry | SentryModule.forRoot() + SentryGlobalFilter |
| 水平扩展 | 无状态设计 + 负载均衡 + Redis Session/Cache |
| Docker Compose | 多服务编排 + 健康检查 + 依赖等待 |
| CI/CD | Lint → Test → Build → Push → Deploy |
| AWS Lambda | @codegenie/serverless-express + LazyModuleLoader |
| nest-commander | CommandRunner + @Command + @Option |
| nestjs-cls | AsyncLocalStorage 替代 Scope.REQUEST |
| 常见错误 | "Cannot resolve dependency" → providers/forwardRef/NEST_DEBUG |
| DevTools | 依赖图、路由导航、Playground、性能分析 |
| 演进路径 | 单体 → 混合 → 微服务集群 → Federation |
| CQRS | CommandBus → Handler → EventBus → EventHandler,QueryBus → Handler |
| @Saga | 事件驱动命令链 |
| 技术决策 | Express/Fastify、Prisma/TypeORM、gRPC/NATS、Docker/Serverless |
九、课程总结 — 20 课 NestJS 全栈之旅
恭喜你完成了 NestJS 全栈深入课程的全部 20 课。让我们回顾这段旅程:
学习路线全景
第一阶段:核心基础(第 1-4 课)
第 1 课 走进 NestJS → 理念、CLI、项目创建
第 2 课 Controller → 路由、参数、版本控制
第 3 课 Provider 与 DI → 依赖注入、自定义 Provider
第 4 课 Module → 模块化、动态模块、Monorepo
第二阶段:请求管线(第 5-8 课)
第 5 课 Middleware + 异常 → 中间件、异常过滤器
第 6 课 Pipe + 验证 → 管道、class-validator、Zod
第 7 课 Guard + Interceptor → 守卫、拦截器、ExecutionContext
第 8 课 Custom Decorator → 自定义装饰器、Discovery Service
第三阶段:DI 深入(第 9 课)
第 9 课 注入作用域与生命周期 → Scope、ModuleRef、forwardRef、生命周期钩子
第四阶段:数据与安全(第 10-12 课)
第 10 课 数据库集成 → TypeORM、Prisma、Mongoose、序列化
第 11 课 认证与授权 → JWT、Passport、RBAC、CASL
第 12 课 安全加固 → Helmet、CORS、CSRF、限流、加密
第五阶段:实用技术(第 13-15 课)
第 13 课 配置、日志与事件 → ConfigModule、Logger、EventEmitter
第 14 课 缓存、队列与定时任务 → cache-manager、BullMQ、@Cron
第 15 课 文件、HTTP 与其他 → 上传、流式、SSE、MVC
第六阶段:通信与 API(第 16-19 课)
第 16 课 WebSocket → Socket.IO、适配器、增强器
第 17 课 微服务 → 7 种传输层、混合应用、自定义传输
第 18 课 GraphQL → Code First、Federation、订阅
第 19 课 API 文档与测试 → Swagger、单元测试、E2E 测试
第七阶段:生产(第 20 课)
第 20 课 生产部署与架构设计 → Docker、CQRS、Serverless、技术全景图
核心能力矩阵
| 能力层次 | 掌握内容 | 可以做什么 |
|---|---|---|
| 基础 | Controller、Service、Module、Pipe、Guard | 独立开发标准 REST API |
| 中阶 | 动态模块、Interceptor、配置、缓存、队列 | 开发生产级企业应用 |
| 高阶 | 微服务、GraphQL、WebSocket、CQRS | 设计复杂分布式系统 |
| 资深 | 源码原理、平台抽象、DI 容器 | 扩展框架、贡献源码 |
| 架构 | 技术选型、演进策略、质量保障 | 主导技术方案和团队建设 |
持续学习建议
- 实践:选择一个真实项目,从单体开始,逐步应用课程中的技术
- 源码:阅读
packages/core/目录,重点关注 DI 容器和请求管线 - 社区:关注 NestJS GitHub 仓库的 Release Notes,跟踪新特性
- 扩展:探索课程未涵盖的主题 — Prisma 高级、Kafka Streams、K8s Operator
NestJS 的核心价值在于:用 Angular 式的架构思维构建 Node.js 后端。掌握了模块化 + DI + 装饰器这三大支柱,你就掌握了 NestJS 的灵魂。无论技术如何演进,这些架构思想都将持续受用。