Appearance
NestJS
导航目录
- NestJS 框架概述
- IoC 与 DI 核心原理
- 组件生命周期
- 模块化架构
- 装饰器深度解析
- RESTful API 设计规范
- 分层架构与对象模型
- Providers 高级用法
- 中间件与拦截器实战
- 异常处理最佳实践
- 管道验证与数据转换
- 项目结构最佳实践
- 最佳实践总结
NestJS 框架概述
核心概念
NestJS 是一个基于 TypeScript 构建的现代化服务器端框架,提供模块化架构和依赖注入系统,支持构建高效、可扩展的应用程序。
NestJS 是一个用于构建高效、可扩展的服务器端应用程序的现代化框架:
- 基于 TypeScript 构建,支持完整的面向对象编程
- 受 Angular 启发,提供模块化架构和依赖注入系统
- 支持 Express 和 Fastify 底层 HTTP 引擎
- 内置路由管理、中间件支持、异常处理等基础设施
- 采用控制反转(IoC) 和 依赖注入(DI) 设计模式
- 提供丰富的装饰器语法简化开发
typescript
// 基础NestJS应用示例
import { Module, Controller, Get } from "@nestjs/common";
import { NestFactory } from "@nestjs/core";
@Controller()
class AppController {
@Get()
getHello() {
return { message: "Hello NestJS!" };
}
}
@Module({
controllers: [AppController],
})
class AppModule {}
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();IoC 与 DI 核心原理
核心概念
IoC(控制反转)和 DI(依赖注入)是 NestJS 的核心设计模式,通过将对象创建和依赖管理交给容器,降低组件间耦合度,提高代码可维护性。
控制反转(IoC)
- 将对象创建的控制权从程序代码转移到外部容器
- 降低组件间的耦合度
- 提高代码灵活性和可维护性
依赖注入(DI)
- IoC 的具体实现方式
- 类不直接创建依赖对象,而是通过构造函数注入
- 容器管理对象的生命周期和依赖关系
typescript
// 依赖注入示例
@Injectable()
class UserService {
getUsers() {
return [{ id: 1, name: "John" }];
}
}
@Controller("users")
class UserController {
// 通过构造函数注入依赖
constructor(private readonly userService: UserService) {}
@Get()
getUsers() {
return this.userService.getUsers();
}
}组件生命周期
核心概念
NestJS 提供了完整的生命周期钩子,允许开发者在应用和模块的不同阶段执行特定逻辑,如初始化、启动和销毁。
NestJS 应用具有明确的生命周期钩子:
- OnModuleInit - 模块初始化完成后调用
- OnApplicationBootstrap - 应用完全启动后调用
- OnModuleDestroy - 模块销毁前调用
- OnApplicationShutdown - 应用关闭前调用
typescript
import { Injectable, OnModuleInit } from "@nestjs/common";
@Injectable()
class DatabaseService implements OnModuleInit {
async onModuleInit() {
// 模块初始化时建立数据库连接
await this.connectToDatabase();
}
private async connectToDatabase() {
// 数据库连接逻辑
}
}模块化架构
核心概念
模块化是 NestJS 的核心特性,通过将应用划分为多个模块,实现高内聚低耦合的架构设计,提高代码可维护性和可测试性。
模块核心功能
typescript
@Module({
imports: [DatabaseModule], // 导入依赖模块
controllers: [UserController], // 注册控制器
providers: [UserService], // 注册服务/提供者
exports: [UserService], // 导出服务供其他模块使用
})
export class UserModule {}全局模块
typescript
@Global() // 声明为全局模块
@Module({
providers: [ConfigService],
exports: [ConfigService],
})
export class ConfigModule {}装饰器深度解析
类装饰器
typescript
// REST控制器装饰器实现原理
function Controller(prefix: string) {
return (target: any) => {
// 存储路由前缀元数据
Reflect.defineMetadata("prefix", prefix, target);
// 添加中间件支持
target.prototype.useMiddleware = function () {
console.log("Applying middleware");
};
};
}
@Controller("/api/users")
class UserController {}方法装饰器(AOP 实现)
typescript
// 执行时间记录装饰器
function LogExecutionTime() {
return (target: any, key: string, descriptor: PropertyDescriptor) => {
const originalMethod = descriptor.value;
descriptor.value = async function (...args: any[]) {
const start = Date.now();
const result = await originalMethod.apply(this, args);
const duration = Date.now() - start;
console.log(`${key} executed in ${duration}ms`);
return result;
};
};
}
class UserService {
@LogExecutionTime()
async getUsers() {
// 模拟耗时操作
await new Promise((resolve) => setTimeout(resolve, 500));
return [];
}
}RESTful API 设计规范
核心概念
RESTful API 设计规范是构建标准化、可维护的 API 接口的重要指南,NestJS 提供了丰富的装饰器来实现 RESTful 路由。
标准资源操作
typescript
@Controller("articles")
export class ArticleController {
// 创建文章 - POST /articles
@Post()
create(@Body() createDto: CreateArticleDto) {}
// 获取文章列表 - GET /articles
@Get()
findAll(@Query() pagination: PaginationDto) {}
// 获取单篇文章 - GET /articles/:id
@Get(":id")
findOne(@Param("id") id: string) {}
// 更新文章 - PATCH /articles/:id
@Patch(":id")
update(@Param("id") id: string, @Body() updateDto: UpdateArticleDto) {}
// 删除文章 - DELETE /articles/:id
@Delete(":id")
remove(@Param("id") id: string) {}
}分层架构与对象模型
阿里巴巴分层规范实践
| 对象类型 | 说明 | 使用场景 |
|---|---|---|
| DO | 数据对象(对应数据库表) | 数据库操作层 |
| DTO | 数据传输对象 | Controller-Service 传输 |
| BO | 业务对象 | Service 层复杂业务逻辑 |
| VO | 视图对象 | 返回给前端的展示数据 |
| Query | 查询对象 | 查询参数封装 |
对象模型实现
typescript
// 数据对象(DO)
@Entity()
class UserDO {
@PrimaryGeneratedColumn()
id: number;
@Column()
username: string;
@Column()
password: string;
}
// 数据传输对象(DTO)
class CreateUserDto {
@IsString()
@MinLength(3)
username: string;
@IsString()
@MinLength(8)
password: string;
}
// 视图对象(VO)
class UserVO {
id: number;
username: string;
avatar: string;
joinDate: string;
}Providers 高级用法
多种提供者类型
typescript
@Module({
providers: [
// 1. 类提供者(标准用法)
UserService,
// 2. 值提供者(配置项)
{ provide: "APP_CONFIG", useValue: { timeout: 3000 } },
// 3. 工厂提供者(动态创建)
{
provide: "DATA_SOURCE",
useFactory: async () => {
const source = new DataSource();
await source.initialize();
return source;
},
},
// 4. 别名提供者
{ provide: "UserServiceAlias", useExisting: UserService },
// 5. 异步提供者
{
provide: "ASYNC_PROVIDER",
useFactory: async () => {
return await Promise.resolve("Async Value");
},
},
],
})
export class AppModule {}中间件与拦截器实战
日志中间件
typescript
@Injectable()
export class LoggerMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
const { method, originalUrl } = req;
const start = Date.now();
res.on("finish", () => {
const duration = Date.now() - start;
console.log(`${method} ${originalUrl} ${res.statusCode} - ${duration}ms`);
});
next();
}
}
// 应用中间件
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(LoggerMiddleware).forRoutes("*");
}
}响应格式化拦截器
typescript
@Injectable()
export class ResponseInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler) {
return next.handle().pipe(
map((data) => ({
code: 200,
timestamp: new Date().toISOString(),
data,
}))
);
}
}
// 全局注册
const app = await NestFactory.create(AppModule);
app.useGlobalInterceptors(new ResponseInterceptor());异常处理最佳实践
自定义业务异常
typescript
// 业务异常基类
export class BusinessException extends HttpException {
constructor(
public readonly code: number,
message: string,
status: number = 400
) {
super({ code, message }, status);
}
}
// 具体业务异常
export class UserNotFoundException extends BusinessException {
constructor() {
super(1001, 'User not found', 404);
}
}
// 使用
@Get(':id')
async getUser(@Param('id') id: string) {
const user = await this.userService.findById(id);
if (!user) {
throw new UserNotFoundException();
}
return user;
}全局异常过滤器
typescript
@Catch()
export class GlobalExceptionFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
let status = 500;
let message = "Internal server error";
let code = 5000;
if (exception instanceof BusinessException) {
status = exception.getStatus();
message = exception.message;
code = exception.code;
} else if (exception instanceof HttpException) {
status = exception.getStatus();
message = exception.message;
}
response.status(status).json({
code,
message,
timestamp: new Date().toISOString(),
});
}
}
// 注册全局过滤器
app.useGlobalFilters(new GlobalExceptionFilter());管道验证与数据转换
核心概念
管道是 NestJS 中处理数据验证和转换的重要机制,用于确保输入数据的正确性和一致性。
自定义验证管道
typescript
@Injectable()
export class ValidationPipe implements PipeTransform {
async transform(value: any, metadata: ArgumentMetadata) {
const { metatype } = metadata;
if (!metatype || !this.toValidate(metatype)) {
return value;
}
const object = plainToClass(metatype, value);
const errors = await validate(object);
if (errors.length > 0) {
throw new BadRequestException(this.formatErrors(errors));
}
return object;
}
private toValidate(metatype: any): boolean {
const types = [String, Boolean, Number, Array, Object];
return !types.includes(metatype);
}
private formatErrors(errors: ValidationError[]) {
return errors.map(err => {
for (const constraint in err.constraints) {
return {
field: err.property,
message: err.constraints[constraint]
};
}
});
}
}
// 使用管道
@Post()
createUser(@Body(ValidationPipe) createUserDto: CreateUserDto) {
// 验证通过的数据
}项目结构最佳实践
核心概念
良好的项目结构是构建可维护应用的基础,NestJS 推荐采用模块化的项目结构,将不同功能的代码分离到不同的目录中。
src/
├── common/ // 公共模块
│ ├── decorators/ // 自定义装饰器
│ ├── filters/ // 异常过滤器
│ ├── interceptors/ // 拦截器
│ ├── pipes/ // 管道
│ └── utils/ // 工具函数
├── modules/ // 业务模块
│ ├── user/
│ │ ├── user.controller.ts
│ │ ├── user.service.ts
│ │ ├── entities/ // 数据实体
│ │ ├── dto/ // 数据传输对象
│ │ └── user.module.ts
│ └── product/
├── config/ // 配置文件
├── app.module.ts // 根模块
└── main.ts // 入口文件最佳实践总结
模块化设计:
- 按业务功能划分模块
- 保持模块高内聚低耦合
- 使用共享模块暴露公共服务
依赖注入:
- 通过构造函数注入依赖
- 避免在服务中直接实例化其他服务
- 使用接口抽象依赖
RESTful 设计:
- 使用合适的 HTTP 方法
- 资源化 URL 设计
- 正确使用 HTTP 状态码
验证与转换:
- 使用 DTO 进行输入验证
- 管道处理数据转换和验证
- 类转换器处理对象映射
异常处理:
- 自定义业务异常类
- 全局异常过滤器统一处理
- 提供有意义的错误信息
性能优化:
- 使用拦截器记录请求时间
- 异步操作使用 Promise.all 优化
- 数据库查询添加索引
安全实践:
- 使用 Helmet 设置安全头
- 验证所有用户输入
- 限制请求负载大小
typescript
// 完整的最佳实践示例
import { Controller, Get, UseInterceptors } from "@nestjs/common";
import { TransformInterceptor } from "./common/interceptors/transform.interceptor";
import { UserService } from "./user/user.service";
@Controller("api")
@UseInterceptors(TransformInterceptor)
export class AppController {
constructor(private readonly userService: UserService) {}
@Get("users")
async getUsers() {
// 业务逻辑与数据访问分离
return this.userService.findAllActiveUsers();
}
}通过遵循这些最佳实践,您可以构建出结构清晰、性能优越、易于维护的 NestJS 应用程序。NestJS 的模块化架构和强大的依赖注入系统使大型应用的开发变得更加高效可控。