FoalTS框架中的Hooks机制深度解析
概述
在FoalTS框架中,Hooks(钩子)是一种强大的装饰器机制,允许开发者在控制器方法执行前后注入额外的逻辑处理。这种设计模式特别适合处理跨切面关注点(cross-cutting concerns),如身份验证、请求验证、日志记录等场景。
Hooks的核心价值
- 代码复用性:将通用逻辑从业务代码中抽离,避免重复代码
- 关注点分离:业务逻辑与横切关注点解耦,提高代码可维护性
- 测试友好:可以独立测试Hook逻辑,简化单元测试
- 执行顺序控制:通过装饰器顺序控制Hook执行流程
内置Hooks详解
FoalTS提供了一系列开箱即用的Hooks:
验证类Hooks
ValidateBody
:验证请求体格式ValidateHeader
:验证请求头ValidatePathParam
:验证路径参数ValidateCookie
:验证CookieValidateQueryParam
:验证查询参数
安全类Hooks
JWTRequired
:强制JWT认证JWTOptional
:可选JWT认证UseSessions
:会话管理PermissionRequired
:权限控制
工具类Hooks
Log
:请求日志记录
使用实践
基本用法
Hooks可以装饰控制器类或方法。类级别的Hook会应用到所有方法和子控制器上。
@JWTRequired() // 应用到所有方法
class ProductController {
@Get('/products')
listProducts() {
// 需要认证
}
@Post('/products')
@ValidateBody(/* schema */) // 方法级别Hook
addProduct() {
// 先验证JWT,再验证请求体
}
}
执行顺序
当多个Hooks装饰同一个方法时,执行顺序遵循以下规则:
- 从类到方法的装饰顺序
- 同一级别的装饰器从下到上执行
自定义Hook开发
基础Hook
import { Hook } from '@foal/core';
function MyHook() {
return Hook(ctx => {
console.log(`Request to ${ctx.request.path}`);
});
}
带服务注入的Hook
function LogHook() {
return Hook((ctx, services) => {
const logger = services.get(LoggerService);
logger.info(ctx.request.method, ctx.request.path);
});
}
后置处理Hook
function TimingHook() {
return Hook(() => {
const start = Date.now();
return () => {
console.log(`耗时: ${Date.now() - start}ms`);
};
});
}
高级技巧
Hook组合
使用MergeHooks
合并多个Hooks:
function SecurityHooks() {
return MergeHooks(
JWTRequired(),
PermissionRequired('admin')
);
}
状态传递
通过ctx.state
在不同Hook间共享数据:
function UserProfileHook() {
return Hook(async ctx => {
if (ctx.user) {
ctx.state.profile = await UserProfile.findOne(ctx.user.id);
}
});
}
测试策略
基础Hook测试
it('should validate request', () => {
const ctx = new Context({ body: { name: 123 } });
const hook = getHookFunction(ValidateBody(schema));
const response = hook(ctx, new ServiceManager());
expect(isHttpResponseBadRequest(response)).toBe(true);
});
服务模拟测试
it('should authenticate user', () => {
const services = new ServiceManager();
services.set(UserService, {
getUser: () => ({ id: 1, name: 'Test' })
});
const ctx = new Context();
const hook = getHookFunction(Authenticate());
hook(ctx, services);
expect(ctx.user).toBeDefined();
});
最佳实践
- 单一职责:每个Hook只处理一个特定功能
- 明确命名:使用动词+名词的命名方式(如
ValidateBody
) - 合理组合:将相关Hooks组合成有意义的单元
- 完善文档:为自定义Hook编写清晰的文档说明
- 全面测试:覆盖各种边界条件
总结
FoalTS的Hooks机制提供了一种优雅的方式来处理Web应用中的横切关注点。通过内置Hooks和自定义Hooks的组合,开发者可以构建出既灵活又易于维护的后端应用架构。理解并合理运用Hooks是掌握FoalTS框架的关键所在。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考