您现在的位置是:网站首页 > NestJS架构文章详情
NestJS架构
陈川
【
Node.js
】
53776人已围观
10027字
NestJS架构概述
NestJS是一个用于构建高效、可扩展的Node.js服务器端应用程序的框架。它使用渐进式JavaScript,内置并完全支持TypeScript,结合了OOP(面向对象编程)、FP(函数式编程)和FRP(函数响应式编程)的元素。NestJS的架构设计借鉴了Angular的模块化思想,提供了一套完整的解决方案,包括依赖注入、模块化、中间件、管道、守卫、拦截器等特性。
核心架构组件
模块系统
NestJS采用模块化的架构设计,每个应用程序至少有一个根模块(通常命名为AppModule
)。模块是组织代码的基本单元,可以包含控制器、提供者和其他模块。
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
})
export class CatsModule {}
模块可以通过imports
数组引入其他模块,通过exports
数组暴露自己的提供者给其他模块使用。这种设计使得应用程序可以很好地解耦和复用代码。
控制器
控制器负责处理传入的请求并返回响应。它们定义了路由和处理程序方法,通常与特定的路径相关联。
import { Controller, Get, Post, Body } from '@nestjs/common';
@Controller('cats')
export class CatsController {
@Get()
findAll(): string {
return 'This action returns all cats';
}
@Post()
create(@Body() createCatDto: CreateCatDto): string {
return 'This action adds a new cat';
}
}
提供者
提供者是NestJS中的一个基本概念,几乎所有的NestJS类都可以被视为提供者 - 服务、仓库、工厂、助手等。提供者通过依赖注入系统在模块内共享。
import { Injectable } from '@nestjs/common';
@Injectable()
export class CatsService {
private readonly cats: Cat[] = [];
create(cat: Cat) {
this.cats.push(cat);
}
findAll(): Cat[] {
return this.cats;
}
}
依赖注入
NestJS内置了强大的依赖注入(DI)系统,这是其架构的核心部分。通过@Injectable()
装饰器标记的类可以被注入到其他类中。
@Controller('cats')
export class CatsController {
constructor(private readonly catsService: CatsService) {}
}
架构分层
表现层
表现层负责处理HTTP请求和响应。这主要包括控制器和相关的DTO(数据传输对象)。控制器应该保持精简,主要处理请求验证和响应格式化,业务逻辑应该委托给服务层。
import { Controller, Get, Query } from '@nestjs/common';
import { CatsService } from './cats.service';
import { PaginationQueryDto } from './dto/pagination-query.dto';
@Controller('cats')
export class CatsController {
constructor(private readonly catsService: CatsService) {}
@Get()
async findAll(@Query() paginationQuery: PaginationQueryDto) {
return this.catsService.findAll(paginationQuery);
}
}
业务逻辑层
业务逻辑层包含应用程序的核心业务规则和逻辑。这一层通常由服务类组成,这些服务类被注入到控制器中。
import { Injectable } from '@nestjs/common';
import { PaginationQueryDto } from './dto/pagination-query.dto';
@Injectable()
export class CatsService {
private readonly cats: Cat[] = [];
findAll(paginationQuery: PaginationQueryDto): Cat[] {
const { limit, offset } = paginationQuery;
return this.cats.slice(offset, offset + limit);
}
}
数据访问层
数据访问层负责与数据源交互,可以是数据库、外部API或其他服务。NestJS提供了多种方式来实现这一层,包括TypeORM、Mongoose等ORM集成。
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Cat } from './cat.entity';
@Injectable()
export class CatsService {
constructor(
@InjectRepository(Cat)
private catsRepository: Repository<Cat>,
) {}
async findAll(): Promise<Cat[]> {
return this.catsRepository.find();
}
}
架构扩展机制
中间件
中间件是在路由处理程序之前调用的函数,可以访问请求和响应对象以及应用程序的请求-响应周期中的next()
中间件函数。
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('Request...');
next();
}
}
异常过滤器
NestJS提供了一个异常层,可以处理应用程序中抛出的所有异常。可以创建自定义异常过滤器来控制精确的响应流和发送给客户端的响应内容。
import { ExceptionFilter, Catch, ArgumentsHost } from '@nestjs/common';
import { HttpException } from '@nestjs/common';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
const status = exception.getStatus();
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
管道
管道有两个典型的用例:转换(将输入数据转换为所需的形式)和验证(评估输入数据,如果有效则简单地传递它,否则抛出异常)。
import { PipeTransform, Injectable, ArgumentMetadata } from '@nestjs/common';
@Injectable()
export class ValidationPipe implements PipeTransform {
transform(value: any, metadata: ArgumentMetadata) {
// 实现验证逻辑
return value;
}
}
守卫
守卫是一个使用@Injectable()
装饰器注释的类,它实现了CanActivate
接口。守卫有一个单一的责任:根据运行时出现的某些条件(如权限、角色、ACL等)确定请求是否应该由路由处理程序处理。
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
const request = context.switchToHttp().getRequest();
return validateRequest(request);
}
}
拦截器
拦截器是受AOP(面向切面编程)启发的强大工具。它们使得在方法执行前后绑定额外的逻辑成为可能,可以转换从方法返回的结果或从方法抛出的异常,扩展基本方法行为,甚至完全覆盖一个方法。
import { Injectable, NestInterceptor, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, call$: Observable<any>): Observable<any> {
console.log('Before...');
const now = Date.now();
return call$.pipe(
tap(() => console.log(`After... ${Date.now() - now}ms`)),
);
}
}
微服务架构支持
NestJS原生支持微服务架构,提供了多种传输层实现,包括TCP、Redis、MQTT等。可以轻松创建混合应用程序,其中部分功能作为微服务运行,而其他部分保留为传统的单体应用程序。
import { NestFactory } from '@nestjs/core';
import { Transport } from '@nestjs/microservices';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.createMicroservice(AppModule, {
transport: Transport.TCP,
options: {
host: 'localhost',
port: 3001,
},
});
app.listen(() => console.log('Microservice is listening'));
}
bootstrap();
可测试性设计
NestJS的架构特别注重可测试性。依赖注入系统使得在测试环境中替换实现变得容易。NestJS提供了专门的测试包@nestjs/testing
来帮助创建测试环境。
import { Test } from '@nestjs/testing';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
describe('CatsController', () => {
let catsController: CatsController;
let catsService: CatsService;
beforeEach(async () => {
const moduleRef = await Test.createTestingModule({
controllers: [CatsController],
providers: [CatsService],
}).compile();
catsService = moduleRef.get<CatsService>(CatsService);
catsController = moduleRef.get<CatsController>(CatsController);
});
describe('findAll', () => {
it('should return an array of cats', async () => {
const result = ['test'];
jest.spyOn(catsService, 'findAll').mockImplementation(() => result);
expect(await catsController.findAll()).toBe(result);
});
});
});
配置管理
NestJS提供了灵活的配置管理方案,可以使用@nestjs/config
包来管理环境变量和应用程序配置。
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
envFilePath: '.env',
}),
],
})
export class AppModule {}
性能优化考虑
NestJS架构设计考虑了性能优化,包括:
- 快速启动:模块系统在应用程序启动时初始化所有依赖项,而不是在请求时
- 中间件优化:中间件执行顺序可以精确控制
- 缓存支持:内置缓存拦截器可以轻松添加缓存层
- 压缩:可以轻松启用响应压缩
import * as compression from 'compression';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(compression());
await app.listen(3000);
}
bootstrap();
生态系统集成
NestJS拥有丰富的生态系统,可以与许多流行的库和技术无缝集成:
- 数据库:TypeORM、Sequelize、Mongoose、Prisma等
- GraphQL:通过
@nestjs/graphql
包提供一流的支持 - WebSockets:通过
@nestjs/websockets
和@nestjs/platform-socket.io
提供支持 - OpenAPI/Swagger:通过
@nestjs/swagger
包自动生成API文档
import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const config = new DocumentBuilder()
.setTitle('Cats example')
.setDescription('The cats API description')
.setVersion('1.0')
.addTag('cats')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
await app.listen(3000);
}
bootstrap();
企业级应用架构模式
对于大型企业应用,NestJS支持多种架构模式:
- 领域驱动设计(DDD):通过模块和提供者自然支持
- 六边形架构:依赖注入使得核心逻辑与基础设施分离
- CQRS:通过
@nestjs/cqrs
包提供支持 - 事件溯源:可以与消息代理如Kafka、RabbitMQ等集成
import { Module } from '@nestjs/common';
import { CqrsModule } from '@nestjs/cqrs';
import { CommandHandlers } from './commands/handlers';
import { EventHandlers } from './events/handlers';
import { QueryHandlers } from './queries/handlers';
@Module({
imports: [CqrsModule],
providers: [
...CommandHandlers,
...EventHandlers,
...QueryHandlers,
],
})
export class AppModule {}
部署架构考虑
NestJS应用程序可以部署在各种环境中:
- 传统服务器:作为Node.js进程运行
- Serverless:适配AWS Lambda、Azure Functions等
- 容器化:使用Docker容器部署
- Kubernetes:作为微服务在K8s集群中运行
# Dockerfile示例
FROM node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["node", "dist/main"]
架构最佳实践
- 保持模块小而专注:每个模块应该有一个明确的职责
- 使用DTO进行输入验证:保持控制器简洁,验证逻辑在DTO中
- 分层架构:清晰分离表现层、业务逻辑层和数据访问层
- 依赖注入:充分利用NestJS的DI系统实现松耦合
- 异常处理统一:使用异常过滤器提供一致的错误响应
- 文档化API:使用Swagger/OpenAPI自动生成文档
- 环境配置分离:使用ConfigModule管理不同环境的配置
- 测试驱动开发:利用NestJS优秀的测试支持编写单元和集成测试
// 示例:分层架构中的DTO
export class CreateCatDto {
@IsString()
@MinLength(1)
@MaxLength(50)
name: string;
@IsInt()
@Min(0)
age: number;
@IsString()
@MinLength(1)
@MaxLength(50)
breed: string;
}