1. Egg.js 进阶实战:参数校验、切面编程与异步任务详解
作为一名长期使用 Egg.js 开发企业级应用的全栈工程师,我发现很多开发者在进阶功能使用上存在误区。今天我将通过实战案例,详细解析 Egg.js 中三个核心进阶特性:参数校验规范实现、AOP 切面编程的工程化应用,以及高可靠异步任务处理方案。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 参数校验:从基础到生产级实践
2.1 为什么需要参数校验?
在 Web 开发中,客户端传入的参数往往不可信任。我曾经历过一次线上事故:由于未对分页参数做校验,攻击者传入 pageSize=1000000 导致数据库过载。规范的参数校验能:
- 防止非法参数导致系统异常
- 统一校验规则,避免散落在业务代码中
- 自动生成清晰的错误响应
2.2 基于 AJV 的校验方案
Egg.js 官方推荐使用 AJV (Another JSON Schema Validator) 进行校验。其优势在于:
- 支持 JSON Schema 标准
- 编译后的校验函数性能极高
- 内置类型转换和格式校验
typescript复制// 定义参数 schema
const UserCreateSchema = Type.Object({
username: Type.String({
minLength: 4,
maxLength: 20,
pattern: '^[a-zA-Z0-9_]+$'
}),
age: Type.Integer({ minimum: 18 }),
email: Type.String({ format: 'email' })
});
// 在 Controller 中使用
@HTTPController()
export class UserController {
@Inject()
private readonly ajv: Ajv;
@HTTPMethod({
method: 'POST',
path: '/users'
})
async create(userData: UserCreateType) {
this.ajv.validate(UserCreateSchema, userData);
// 业务逻辑...
}
}
2.3 生产环境最佳实践
- 统一错误处理:通过中间件捕获
AjvInvalidParamError,返回标准错误格式 - Schema 复用:将常用 Schema 提取到
app/schema目录 - 自定义校验规则:通过
ajv.addKeyword()扩展业务规则
typescript复制// 自定义手机号校验规则
ajv.addKeyword({
keyword: 'isMobile',
validate: (schema: boolean, data: string) => {
return /^1[3-9]\d{9}$/.test(data);
}
});
3. 切面编程:提升代码可维护性
3.1 AOP 核心概念图解
code复制[客户端请求]
|
v
[Controller] ---> [Service] ---> [Model]
| | |
v v v
[日志记录] [事务管理] [缓存处理]
3.2 五种通知类型详解
- Before Advice:方法执行前
- 典型应用:参数预处理、权限校验
- AfterReturning:方法成功返回后
- 典型应用:结果日志记录
- AfterThrowing:方法抛出异常后
- 典型应用:异常监控上报
- AfterFinally:方法最终结束时
- 典型应用:资源清理
- Around:包裹整个方法
- 典型应用:性能监控、事务管理
3.3 事务管理实战案例
typescript复制@Advice()
export class TransactionAdvice implements IAdvice {
@Inject()
private dataSource: DataSource;
async around(ctx: AdviceContext, next: () => Promise<any>) {
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
const result = await next();
await queryRunner.commitTransaction();
return result;
} catch (error) {
await queryRunner.rollbackTransaction();
throw error;
} finally {
await queryRunner.release();
}
}
}
// 使用示例
@SingletonProto()
export class OrderService {
@Pointcut(TransactionAdvice)
async createOrder(orderData: OrderDTO) {
// 业务逻辑...
}
}
3.4 性能监控切面实现
typescript复制@Advice()
export class PerformanceAdvice implements IAdvice {
@Inject()
private metrics: MetricsService;
async around(ctx: AdviceContext, next: () => Promise<any>) {
const start = Date.now();
try {
return await next();
} finally {
const cost = Date.now() - start;
this.metrics.record(
`${ctx.that.constructor.name}.${String(ctx.method)}`,
cost
);
}
}
}
4. 异步任务处理:可靠性与性能平衡
4.1 异步任务适用场景
- 非核心流程(如发送通知)
- 耗时操作(如文件处理)
- 第三方服务调用(如支付回调)
4.2 超时控制机制
typescript复制@SingletonProto()
export class ReportService {
@Inject()
private backgroundTaskHelper: BackgroundTaskHelper;
async generateReport(userId: string) {
// 设置10秒超时
this.backgroundTaskHelper.timeout = 10000;
this.backgroundTaskHelper.run(async () => {
const report = await this.buildComplexReport(userId);
await this.sendEmail(userId, report);
});
}
}
4.3 错误处理与重试策略
typescript复制this.backgroundTaskHelper.run(async (ctx) => {
try {
await doSomething();
} catch (error) {
if (ctx.retryCount < 3) {
ctx.retryAfter(1000); // 1秒后重试
} else {
await this.errorHandler(error);
}
}
});
5. 常见问题排查指南
5.1 AJV 校验不生效
现象:校验规则未触发
排查步骤:
- 检查
ajv.validate()是否被调用 - 确认 Schema 定义是否正确导出
- 查看中间件是否拦截了错误
5.2 切面未执行
可能原因:
- 未添加
@Advice()装饰器 - Pointcut 表达式匹配失败
- 类未被 Egg.js 容器管理
5.3 异步任务丢失
解决方案:
- 增加任务队列持久化
- 实现幂等处理
- 添加补偿机制
typescript复制// 持久化任务示例
this.backgroundTaskHelper.run(async () => {
const task = await this.taskRepo.create({ status: 'processing' });
try {
await processTask(task);
await this.taskRepo.update(task.id, { status: 'completed' });
} catch (error) {
await this.taskRepo.update(task.id, { status: 'failed' });
}
});
6. 性能优化建议
- AJV 编译缓存:复用编译后的校验函数
- 切面排序:通过
order属性控制切面执行顺序 - 异步任务分流:根据任务类型使用不同线程池
typescript复制// 切面排序示例
@Advice({ order: 100 })
export class LogAdvice implements IAdvice {
// ...
}
@Advice({ order: 200 })
export class TransactionAdvice implements IAdvice {
// ...
}
在实际项目开发中,合理运用这些进阶特性可以显著提升代码质量和可维护性。特别是在微服务架构下,规范的参数校验和统一的切面处理能大幅降低系统间的集成成本。对于异步任务,建议结合消息队列实现更可靠的分布式任务处理。
