Skip to content

元数据与执行生命周期

每次装饰方法调用解析新的 exchange,同时复用实例级、方法级执行器。钩子运行在服务实例上;并发调用可能重叠时,不要把请求专属可变状态存在该实例上。

逐次添加 exchange 属性或选择提取器时使用 beforeExecute;检查已通过校验的响应而不消费响应体时使用 afterExecute。两者都可省略,没有默认动作。只有构建运行时扩展才直接调用 RequestExecutor 或操作 FunctionMetadata,普通服务无需使用它们。

RequestExecutor 生命周期

new RequestExecutor(target: any, metadata: FunctionMetadata)execute(args: any[]): Promise<any> 按下列顺序执行:

  1. 解析 Fetcher,把参数合并到 request/attributes。
  2. DECORATOR_TARGET_ATTRIBUTE_KEY = '__decorator_target__'DECORATOR_METADATA_ATTRIBUTE_KEY = '__decorator_metadata__' 下保存目标及元数据。
  3. 使用选定提取器调用 fetcher.resolveExchange
  4. 等待可选 ExecuteLifeCycle.beforeExecute(exchange)
  5. 等待 fetcher.interceptors.exchange(exchange)
  6. 等待可选 ExecuteLifeCycle.afterExecute(exchange)
  7. 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_KEYPARAMETER_METADATA_KEY 在原型/属性上存方法和参数元数据。它们是导出的 Symbol,不是可用 Symbol(...) 重建的稳定字符串键。

buildRequestExecutor(target, defaultFunctionMetadata): RequestExecutor 创建/复用 target.requestExecutors: Map<string, RequestExecutor>,首次使用时浅合并实例 apiMetadata。此公开接口供生成器/扩展使用,普通用户直接调用装饰方法。api 遍历原型链,每个名称只绑定最近的字符串命名函数,在保留继承元数据查询的同时,把执行器安装到装饰类。避免把 requestExecutors 用作业务实例字段。

下面在独立客户端替换网络拦截器,以无服务方式记录解析调用。这是测试设置,不是生产重试机制。

完整示例

ts
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_KEYapiDecorator.ts:90
buildRequestExecutorapiDecorator.ts:164
ENDPOINT_METADATA_KEYendpointDecorator.ts:31
EndpointReturnTypeendpointReturnTypeCapable.ts:14
EndpointReturnTypeCapableendpointReturnTypeCapable.ts:19
ExecuteLifeCycleexecuteLifeCycle.ts:23
FunctionMetadatafunctionMetadata.ts:100
DECORATOR_TARGET_ATTRIBUTE_KEYrequestExecutor.ts:17
DECORATOR_METADATA_ATTRIBUTE_KEYrequestExecutor.ts:18
RequestExecutorrequestExecutor.ts:61

包索引

基于 Apache License 2.0 发布。