元数据与执行生命周期
每次装饰方法调用解析新的 exchange,同时复用实例级、方法级执行器。钩子运行在服务实例上;并发调用可能重叠时,不要把请求专属可变状态存在该实例上。
逐次添加 exchange 属性或选择提取器时使用 beforeExecute;检查已通过校验的响应而不消费响应体时使用 afterExecute。两者都可省略,没有默认动作。只有构建运行时扩展才直接调用 RequestExecutor 或操作 FunctionMetadata,普通服务无需使用它们。
RequestExecutor 生命周期
new RequestExecutor(target: any, metadata: FunctionMetadata) 与 execute(args: any[]): Promise<any> 按下列顺序执行:
- 解析 Fetcher,把参数合并到 request/attributes。
- 在
DECORATOR_TARGET_ATTRIBUTE_KEY = '__decorator_target__'和DECORATOR_METADATA_ATTRIBUTE_KEY = '__decorator_metadata__'下保存目标及元数据。 - 使用选定提取器调用
fetcher.resolveExchange。 - 等待可选
ExecuteLifeCycle.beforeExecute(exchange)。 - 等待
fetcher.interceptors.exchange(exchange)。 - 等待可选
ExecuteLifeCycle.afterExecute(exchange)。 - EXCHANGE 模式返回 exchange,否则等待
exchange.extractResult()。
两个钩子都返回 void | Promise<void>。before 先于正文/URL 拦截器,after 在响应校验后、提取前运行;都不是 finally 钩子。before 拒绝阻止 I/O,管线拒绝跳过 after,after 拒绝阻止提取。钩子及提取器失败不在管理器错误拦截器捕获范围内。无条件清理使用调用者 try/finally。
EndpointReturnType.EXCHANGE = 'Exchange' 返回 exchange 而不提取;RESULT = 'Result' 是默认值。EndpointReturnTypeCapable.returnType? 提供此选项,不根据方法返回类型推断模式。
FunctionMetadata
new FunctionMetadata(name, api, endpoint, parameters: Map<number, ParameterMetadata>) 保留这些公开字段。其方法与装饰方法使用相同解析逻辑:
| 成员 | 返回值 / 优先级 |
|---|---|
fetcher | 从端点、API、全局注册表解析所需 Fetcher,缺失注册时抛错。 |
resolvePath(parameterPath?) | 按真值回退选择端点/API basePath 与参数/端点 path,再拼接;绝对端点地址覆盖基础路径。 |
resolveTimeout() | 端点已定义值,再 API;客户端回退随后应用。 |
resolveResultExtractor() | 端点、API、默认 JSON。 |
resolveAttributes() | 新 Map,API 条目后写入端点条目。 |
resolveEndpointReturnType() | 端点、API、默认 RESULT。 |
resolveExchangeInit(args) | 仅返回必填 request 与 attributes,完成绑定/request 合并,不发 HTTP。 |
反射与缓存
API_METADATA_KEY 在构造器上存类元数据;ENDPOINT_METADATA_KEY、PARAMETER_METADATA_KEY 在原型/属性上存方法和参数元数据。它们是导出的 Symbol,不是可用 Symbol(...) 重建的稳定字符串键。
buildRequestExecutor(target, defaultFunctionMetadata): RequestExecutor 创建/复用 target.requestExecutors: Map<string, RequestExecutor>,首次使用时浅合并实例 apiMetadata。此公开接口供生成器/扩展使用,普通用户直接调用装饰方法。api 遍历原型链,每个名称只绑定最近的字符串命名函数,在保留继承元数据查询的同时,把执行器安装到装饰类。避免把 requestExecutors 用作业务实例字段。
下面在独立客户端替换网络拦截器,以无服务方式记录解析调用。这是测试设置,不是生产重试机制。
完整示例
import {
Fetcher,
FETCH_INTERCEPTOR_NAME,
FETCH_INTERCEPTOR_ORDER,
type FetchExchange,
} from '@ahoo-wang/fetcher';
import {
api,
get,
autoGeneratedError,
type ExecuteLifeCycle,
} from '@ahoo-wang/fetcher-decorator';
const client = new Fetcher({ baseURL: 'https://example.com' });
client.interceptors.request.eject(FETCH_INTERCEPTOR_NAME);
client.interceptors.request.use({
name: 'local-response',
order: FETCH_INTERCEPTOR_ORDER,
intercept(exchange) {
exchange.response = Response.json({ ok: true });
},
});
@api('/health', { fetcher: client })
class Health implements ExecuteLifeCycle {
beforeExecute(exchange: FetchExchange) {
exchange.attributes.set('started', true);
}
afterExecute(exchange: FetchExchange) {
console.assert(exchange.response?.status === 200);
}
@get()
check(): Promise<{ ok: boolean }> {
throw autoGeneratedError();
}
}
console.assert((await new Health().check()).ok);公开符号与源码
| 符号 | 实现 |
|---|---|
API_METADATA_KEY | apiDecorator.ts:90 |
buildRequestExecutor | apiDecorator.ts:164 |
ENDPOINT_METADATA_KEY | endpointDecorator.ts:31 |
EndpointReturnType | endpointReturnTypeCapable.ts:14 |
EndpointReturnTypeCapable | endpointReturnTypeCapable.ts:19 |
ExecuteLifeCycle | executeLifeCycle.ts:23 |
FunctionMetadata | functionMetadata.ts:100 |
DECORATOR_TARGET_ATTRIBUTE_KEY | requestExecutor.ts:17 |
DECORATOR_METADATA_ATTRIBUTE_KEY | requestExecutor.ts:18 |
RequestExecutor | requestExecutor.ts:61 |
