一、模块化设计
TypeScript
// user.module.ts
@Module({
controllers: [UserController], // 当前模块的控制器
providers: [UserService], // 当前模块的服务
exports: [UserService] // 暴露给其他模块使用的服务
})
export class UserModule {}
// order.module.ts
@Module({
imports: [UserModule], // 导入依赖模块
controllers: [OrderController],
providers: [OrderService]
})
export class OrderModule {}
核心逻辑:
- 每个业务域(用户/订单)独立成模块
- 模块间通过
imports
建立依赖关系 - 使用
exports
控制服务可见性
开发建议:
- 按业务功能而非技术分层划分模块
- 公共组件(数据库连接、配置)使用共享模块
- 避免循环依赖(使用
forwardRef
必要时)
典型问题:
TypeScript
// 循环依赖解决方案
@Module({
imports: [forwardRef(() => OrderModule)]
})
export class UserModule {}
二、依赖注入机制
TypeScript
// 自定义Provider示例
@Injectable()
export class DatabaseService {
constructor(@Inject('CONFIG_OPTIONS') private options) {}
}
// 动态模块配置
@Module({})
export class DatabaseModule {
static register(options): DynamicModule {
return {
module: DatabaseModule,
providers: [
{
provide: 'CONFIG_OPTIONS',
useValue: options
},
DatabaseService
]
};
}
}
设计优势:
- 通过构造函数自动注入依赖
- 支持接口与实现分离
- 方便进行单元测试(Mock依赖)
使用注意:
- 避免在构造函数执行耗时操作
- 合理使用作用域(默认单例)
- 复杂对象推荐使用工厂模式创建
三、渐进式架构实践
TypeScript
// 从基础到高级的演进示例
// 1. 基础Controller
@Controller('users')
export class BasicUserController {
@Get()
findAll() {
return [{ id: 1, name: 'test' }];
}
}
// 2. 添加DTO验证
export class CreateUserDto {
@IsString()
@MinLength(3)
name: string;
}
@Post()
create(@Body() createUserDto: CreateUserDto) {
// 业务逻辑
}
// 3. 添加拦截器
@UseInterceptors(TransformInterceptor)
@Get(':id')
findOne(@Param('id') id: string) {
return this.userService.findOne(id);
}
演进策略:
- 初期:快速建立路由层+基础服务
- 中期:添加验证管道、异常过滤器
- 后期:引入CQRS、微服务架构
性能注意点:
- 拦截器/管道链长度影响吞吐量
- 全局中间件慎用复杂逻辑
- 监控请求处理时间(推荐接入Prometheus)
四、可扩展性实现
TypeScript
// 自定义Transport示例
@Injectable()
export class KafkaTransport extends Server {
constructor(private config: KafkaConfig) {
super();
}
listen(callback: () => void) {
// 实现Kafka消费者逻辑
}
}
// 配置微服务
const app = await NestFactory.createMicroservice(AppModule, {
strategy: new KafkaTransport(kafkaConfig)
});
扩展方向:
- Transport层(支持gRPC/WebSocket/MQTT)
- 存储抽象(兼容不同数据库)
- 认证策略(OAuth2/JWT/LDAP)
开发建议:
- 使用适配器模式封装第三方服务
- 核心业务保持框架无关性
- 通过装饰器组合实现横切关注点
五、错误处理最佳实践
TypeScript
// 自定义异常过滤器
@Catch(CustomBusinessException)
export class BusinessExceptionFilter implements ExceptionFilter {
catch(exception: CustomBusinessException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
response.status(400).json({
code: exception.errorCode,
message: exception.message,
timestamp: new Date().toISOString()
});
}
}
// 控制器使用示例
@Post()
@UseFilters(BusinessExceptionFilter)
async create(@Body() userDto: CreateUserDto) {
return this.userService.create(userDto);
}
错误处理策略:
- 业务异常与系统异常分类处理
- 全局过滤器兜底未知异常
- HTTP状态码与业务状态码分离
六、性能优化建议
TypeScript
// 缓存装饰器示例
@Injectable()
export class CacheManager {
async get<T>(key: string): Promise<T> {
// Redis实现
}
}
@Controller('products')
export class ProductController {
constructor(private cacheManager: CacheManager) {}
@Get(':id')
@UseInterceptors(CacheInterceptor)
async findOne(@Param('id') id: string) {
const cacheKey = `product_${id}`;
const cached = await this.cacheManager.get(cacheKey);
return cached || this.service.findOne(id);
}
}
优化方向:
- 高频读操作添加缓存层
- 批量接口支持分页/游标
- 数据库查询使用索引优化
- 耗时操作异步处理(推荐使用Bull队列)
七、测试策略
TypeScript
// 单元测试示例
describe('UserService', () => {
let service: UserService;
let mockRepository: jest.Mocked<UserRepository>;
beforeEach(async () => {
mockRepository = {
findOne: jest.fn().mockResolvedValue({ id: 1, name: 'test' })
};
const module: TestingModule = await Test.createTestingModule({
providers: [
UserService,
{ provide: UserRepository, useValue: mockRepository }
]
}).compile();
service = module.get<UserService>(UserService);
});
it('should find user by id', async () => {
const result = await service.findOne(1);
expect(mockRepository.findOne).toBeCalledWith(1);
expect(result.name).toBe('test');
});
});
测试建议:
- 服务层使用Jest+Mock测试
- 控制器测试关注HTTP响应格式
- E2E测试覆盖核心业务流程
- 使用TestContainers进行集成测试
- 模块设计遵循高内聚原则,单个模块代码不超过500行
- 公共中间件通过GlobalModule注册
- 使用CLI生成基础代码(nest generate service)
- 生产环境开启请求限流(推荐@nestjs/throttler)
- 接口文档使用Swagger模块自动生成
- 配置管理推荐使用@nestjs/config+环境变量
- 日志系统接入ELK等聚合工具
通过合理运用NestJS的架构特性,可以构建出既保持灵活扩展性,又具备高效执行效率的后端服务。
关键在于平衡框架规范与业务实际需求,避免过度设计的同时保证关键组件的可维护性。