Midway.js 最佳实践
通过前面的学习,您已经掌握了 Midway.js 的核心概念。让我们总结一些最佳实践,帮助您构建更好的应用。
项目结构最佳实践
推荐的目录结构
src/├── controller/ # 控制器│ ├── user.controller.ts│ ├── auth.controller.ts│ └── post.controller.ts├── service/ # 服务层│ ├── user.service.ts│ ├── auth.service.ts│ └── post.service.ts├── middleware/ # 中间件│ ├── auth.middleware.ts│ ├── logger.middleware.ts│ └── error.middleware.ts├── filter/ # 过滤器│ └── default.filter.ts├── dto/ # 数据传输对象│ ├── user.dto.ts│ └── auth.dto.ts├── entity/ # 数据库实体│ └── user.entity.ts├── error/ # 自定义错误│ └── custom.error.ts├── util/ # 工具函数│ └── crypto.util.ts├── config/ # 配置文件│ ├── config.default.ts│ ├── config.local.ts│ └── config.prod.ts├── interface.ts # TypeScript 接口定义├── configuration.ts # 应用配置└── bootstrap.ts # 启动文件代码组织原则
1. 单一职责原则
每个类应该只有一个职责:
// ✅ 好的做法 - 职责清晰@Provide()export class UserService { async findById(id: number) { } async create(data: any) { } async update(id: number, data: any) { }}
@Provide()export class EmailService { async sendWelcomeEmail(email: string) { } async sendResetPasswordEmail(email: string) { }}
// ❌ 不好的做法 - 职责混乱@Provide()export class UserService { async findById(id: number) { } async sendWelcomeEmail(email: string) { } async uploadAvatar(file: any) { }}2. 依赖倒置
依赖抽象而不是具体实现:
// 定义接口export interface IUserRepository { findById(id: number): Promise<User>; create(user: User): Promise<User>;}
// 实现接口@Provide()export class UserRepository implements IUserRepository { async findById(id: number) { // 数据库查询 }
async create(user: User) { // 数据库插入 }}
// Service 依赖接口@Provide()export class UserService { @Inject() userRepository: IUserRepository; // 依赖接口,不是具体实现
async getUser(id: number) { return this.userRepository.findById(id); }}3. 合理使用异步
// ✅ 好的做法 - 使用 async/await@Provide()export class UserService { async createUser(data: any) { const user = await this.userRepository.create(data); await this.emailService.sendWelcomeEmail(user.email); return user; }}
// ❌ 不好的做法 - 回调地狱@Provide()export class UserService { createUser(data: any, callback: Function) { this.userRepository.create(data, (err, user) => { if (err) return callback(err); this.emailService.sendWelcomeEmail(user.email, (err) => { if (err) return callback(err); callback(null, user); }); }); }}API 设计最佳实践
1. RESTful 规范
@Controller('/api/users')export class UserController { @Get('/') async list() { }
@Get('/:id') async detail(@Param('id') id: string) { }
@Post('/') async create(@Body() dto: CreateUserDTO) { }
@Put('/:id') async update(@Param('id') id: string, @Body() dto: UpdateUserDTO) { }
@Patch('/:id') async patch(@Param('id') id: string, @Body() dto: Partial<UpdateUserDTO>) { }
@Del('/:id') async delete(@Param('id') id: string) { }}2. 统一响应格式
// 定义响应接口export interface ApiResponse<T = any> { success: boolean; data?: T; message?: string; code?: string; timestamp?: string;}
// 在 Controller 中使用@Controller('/api/users')export class UserController { @Get('/:id') async detail(@Param('id') id: string): Promise<ApiResponse> { const user = await this.userService.findById(parseInt(id));
if (!user) { return { success: false, message: '用户不存在', code: 'USER_NOT_FOUND', }; }
return { success: true, data: user, timestamp: new Date().toISOString(), }; }}单元测试最佳实践
Midway 推荐使用 @midwayjs/mock 配合 Jest 做接口测试。
安装依赖:
npm install -D @midwayjs/mockpackage.json:
{ "devDependencies": { "@midwayjs/mock": "^4.0.0" }}示例测试:
import { createApp, close, createHttpRequest } from '@midwayjs/mock';import { Framework, Application } from '@midwayjs/koa';
describe('test/controller/home.test.ts', () => { let app: Application;
beforeAll(async () => { // 只创建一次 app,测试用例复用 app = await createApp<Framework>(); });
afterAll(async () => { // 关闭 app 释放资源 await close(app); });
it('should GET /', async () => { const result = await createHttpRequest(app).get('/');
expect(result.status).toBe(200); expect(result.text).toBe('Hello Midwayjs!'); });});安全性最佳实践
-
输入验证
- 所有用户输入必须验证
- 使用 DTO 和验证装饰器
-
身份认证
- 使用 JWT 或 Session
- 重要操作需要二次验证
-
权限控制
- 基于角色的访问控制(RBAC)
- 最小权限原则
-
敏感信息保护
- 密码加密存储(bcrypt)
- API 密钥使用环境变量
- 不在日志中输出敏感数据
性能优化最佳实践
-
缓存
- 使用 Redis 缓存热点数据
- 设置合理的缓存过期时间
-
数据库优化
- 避免 N+1 查询
- 使用索引优化查询
- 合理分页
-
异步任务
- 耗时任务使用队列
- 邮件发送异步处理
-
限流
- 防止接口被滥用
- 使用中间件实现限流
日志与监控最佳实践
-
结构化日志
- 记录关键业务日志
- 包含请求 ID 便于追踪
-
错误监控
- 使用 Sentry 等工具
- 及时报警
-
性能监控
- 监控接口响应时间
- 监控系统资源使用
部署最佳实践
-
环境隔离
- 开发/测试/生产环境严格分离
- 使用不同的配置文件
-
CI/CD
- 自动化测试
- 自动化部署
-
容器化
- 使用 Docker 部署
- 配合 Kubernetes 管理
小结
✅ 合理组织项目结构 ✅ 遵循单一职责原则 ✅ 设计规范的 RESTful API ✅ 统一响应格式 ✅ 使用测试保障质量 ✅ 关注安全、性能与监控
恭喜!您已经完成了 Midway.js 的核心教程!
Files
Preparing Environment
- npm install
- npm run dev