Appearance
NestJS架构
NestJS采用模块化的架构模式,借鉴了Angular的设计理念,使得应用程序结构清晰、可维护性强。本章详细介绍NestJS的架构模式和组件。
应用程序架构
三层架构模式
NestJS应用程序通常遵循经典的三层架构:
┌─────────────────┐
│ Presentation │ ← 控制器 (Controllers)
├─────────────────┤
│ Business Logic│ ← 服务/提供者 (Services/Providers)
├─────────────────┤
│ Data Access │ ← 数据库、外部服务 (Database/External APIs)
└─────────────────┘
模块化架构
NestJS采用模块化的架构,每个模块负责特定的功能:
typescript
// app.module.ts
import { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module';
import { PostsModule } from './posts/posts.module';
import { DatabaseModule } from './database/database.module';
@Module({
imports: [
DatabaseModule,
UsersModule,
PostsModule,
],
controllers: [],
providers: [],
})
export class AppModule {}
模块 (Modules)
模块定义
模块是带有@Module()装饰器的类,用于组织应用程序的组件:
typescript
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
exports: [CatsService], // 导出服务供其他模块使用
})
export class CatsModule {}
模块元数据
@Module()装饰器接受以下元数据:
providers- 由Nest注入器实例化的提供者,并至少在该模块中可用controllers- 应该被实例化的控制器列表imports- 导入模块列表,这些模块导出的提供者在此模块中需要exports- 导出提供者的子集,这些提供者在其他模块中可用module- 可选的模块类引用scope- 模块注入范围
核心模块
typescript
// core/core.module.ts
import { Module, Global } from '@nestjs/common';
import { LoggerService } from './logger.service';
import { ConfigService } from './config.service';
@Global() // 全局模块
@Module({
providers: [
LoggerService,
ConfigService,
],
exports: [
LoggerService,
ConfigService,
],
})
export class CoreModule {}
功能模块
typescript
// users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { DatabaseModule } from '../database/database.module';
import { LoggerService } from '../core/logger.service';
@Module({
imports: [DatabaseModule], // 导入依赖模块
controllers: [UsersController],
providers: [
UsersService,
LoggerService, // 局部提供者
],
exports: [UsersService], // 导出供其他模块使用
})
export class UsersModule {}
控制器 (Controllers)
控制器定义
控制器负责处理传入的请求和返回响应给客户端:
typescript
import {
Controller,
Get,
Post,
Put,
Delete,
Param,
Body,
Query,
HttpStatus,
HttpCode,
Header,
Res,
UseGuards,
UseInterceptors,
UsePipes,
UseFilters
} from '@nestjs/common';
import { Response } from 'express';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { ValidationPipe } from '../pipes/validation.pipe';
import { RolesGuard } from '../guards/roles.guard';
import { LoggingInterceptor } from '../interceptors/logging.interceptor';
import { HttpExceptionFilter } from '../filters/http-exception.filter';
@Controller('users')
@UseGuards(RolesGuard) // 应用守卫
@UseInterceptors(LoggingInterceptor) // 应用拦截器
@UsePipes(ValidationPipe) // 应用管道
@UseFilters(HttpExceptionFilter) // 应用过滤器
export class UsersController {
constructor(private usersService: UsersService) {}
@Get()
@HttpCode(HttpStatus.OK)
@Header('Cache-Control', 'max-age=3600')
async findAll(@Query() query: any): Promise<any[]> {
return this.usersService.findAll(query);
}
@Get(':id')
@UseGuards(RolesGuard) // 在特定方法上应用守卫
async findOne(@Param('id') id: string): Promise<any> {
return this.usersService.findOne(id);
}
@Post()
@HttpCode(HttpStatus.CREATED)
async create(@Body() createUserDto: CreateUserDto): Promise<any> {
return this.usersService.create(createUserDto);
}
@Put(':id')
async update(
@Param('id') id: string,
@Body() updateUserDto: any
): Promise<any> {
return this.usersService.update(id, updateUserDto);
}
@Delete(':id')
@HttpCode(HttpStatus.NO_CONTENT)
async remove(@Param('id') id: string): Promise<void> {
await this.usersService.remove(id);
}
@Get('stream/:id')
async stream(@Param('id') id: string, @Res() res: Response) {
const user = await this.usersService.findOne(id);
res.status(HttpStatus.OK).json(user);
}
}
服务和提供者 (Services and Providers)
服务定义
服务是处理业务逻辑的类:
typescript
import { Injectable, Inject, Scope } from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { Request } from 'express';
import { DatabaseService } from '../database/database.service';
import { LoggerService } from '../core/logger.service';
@Injectable() // 标记为可注入的服务
export class UsersService {
constructor(
private databaseService: DatabaseService,
private loggerService: LoggerService,
) {}
async findAll(query: any): Promise<any[]> {
this.loggerService.log('Finding all users', 'UsersService');
return this.databaseService.find('users', query);
}
async findOne(id: string): Promise<any> {
this.loggerService.log(`Finding user with id: ${id}`, 'UsersService');
return this.databaseService.findOne('users', id);
}
async create(userData: any): Promise<any> {
this.loggerService.log('Creating user', 'UsersService');
return this.databaseService.create('users', userData);
}
async update(id: string, userData: any): Promise<any> {
this.loggerService.log(`Updating user with id: ${id}`, 'UsersService');
return this.databaseService.update('users', id, userData);
}
async remove(id: string): Promise<void> {
this.loggerService.log(`Removing user with id: ${id}`, 'UsersService');
await this.databaseService.delete('users', id);
}
}
请求范围的服务
typescript
import { Injectable, Scope } from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { Request } from 'express';
@Injectable({ scope: Scope.REQUEST }) // 请求范围的服务
export class RequestContextService {
constructor(@Inject(REQUEST) private request: Request) {}
getRequestId(): string {
return this.request.headers['x-request-id'] as string || 'unknown';
}
getUserFromRequest(): any {
return this.request.user;
}
}
分层架构最佳实践
数据传输对象 (DTOs)
typescript
// dto/create-user.dto.ts
import { IsString, IsEmail, IsNumber, Min, Max } from 'class-validator';
export class CreateUserDto {
@IsString()
readonly name: string;
@IsEmail()
readonly email: string;
@IsNumber()
@Min(0)
@Max(120)
readonly age: number;
}
// dto/update-user.dto.ts
import { PartialType } from '@nestjs/mapped-types';
import { CreateUserDto } from './create-user.dto';
export class UpdateUserDto extends PartialType(CreateUserDto) {}
实体 (Entities)
typescript
// entities/user.entity.ts
import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn } from 'typeorm';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column({ unique: true })
email: string;
@Column()
password: string;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
}
模块依赖关系
循环依赖处理
typescript
// users/users.module.ts
import { Module, forwardRef } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { AuthModule } from '../auth/auth.module';
@Module({
imports: [
forwardRef(() => AuthModule), // 处理循环依赖
],
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}
共享模块
typescript
// shared/shared.module.ts
import { Module, Global } from '@nestjs/common';
import { CacheService } from './cache/cache.service';
import { LoggingService } from './logging/logging.service';
import { ValidationService } from './validation/validation.service';
@Global() // 全局共享模块
@Module({
providers: [
CacheService,
LoggingService,
ValidationService,
],
exports: [
CacheService,
LoggingService,
ValidationService,
],
})
export class SharedModule {}
微服务架构
微服务模块
typescript
// microservices/users-ms.module.ts
import { Module } from '@nestjs/common';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { UsersMsService } from './users-ms.service';
@Module({
imports: [
ClientsModule.register([
{
name: 'USER_SERVICE',
transport: Transport.TCP,
options: {
host: 'localhost',
port: 8877,
},
},
]),
],
providers: [UsersMsService],
exports: [UsersMsService],
})
export class UsersMsModule {}
应用程序引导
主入口点
typescript
// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from './pipes/validation.pipe';
import { HttpExceptionFilter } from './filters/http-exception.filter';
import { LoggingInterceptor } from './interceptors/logging.interceptor';
import { TimeoutInterceptor } from './interceptors/timeout.interceptor';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 全局中间件
app.useGlobalFilters(new HttpExceptionFilter());
app.useGlobalPipes(new ValidationPipe());
app.useGlobalInterceptors(
new LoggingInterceptor(),
new TimeoutInterceptor(),
);
// 其他配置
app.setGlobalPrefix('api');
app.enableCors();
await app.listen(3000);
}
bootstrap();
架构模式
仓储模式
typescript
// repositories/user.repository.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from '../entities/user.entity';
@Injectable()
export class UserRepository {
constructor(
@InjectRepository(User)
private userRepository: Repository<User>,
) {}
async findAll(): Promise<User[]> {
return this.userRepository.find();
}
async findById(id: number): Promise<User> {
return this.userRepository.findOne({ where: { id } });
}
async create(user: User): Promise<User> {
return this.userRepository.save(user);
}
async update(id: number, user: User): Promise<User> {
await this.userRepository.update(id, user);
return this.findById(id);
}
async delete(id: number): Promise<void> {
await this.userRepository.delete(id);
}
}
仓库模式的模块
typescript
// users/users.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from '../entities/user.entity';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { UserRepository } from '../repositories/user.repository';
@Module({
imports: [
TypeOrmModule.forFeature([User]), // 注册实体
],
controllers: [UsersController],
providers: [
UsersService,
UserRepository, // 注册仓储
],
exports: [UsersService],
})
export class UsersModule {}
NestJS的架构设计遵循了关注点分离和单一职责原则,使得应用程序易于测试、维护和扩展。