Skip to content

请求和响应拦截

SDK 支持一组 client 级 hooks,用来在请求发出前、返回结果交给业务代码前,以及错误发生时接管处理逻辑。

最小示例

ts
import lsData from '@loongship-kit/data';

const client = lsData.create({
  hooks: {
    async onRequest(context) {
      return {
        ...context,
        requestOptions: {
          ...context.requestOptions,
          headers: {
            ...context.requestOptions.headers,
            'X-Trace-Id': crypto.randomUUID()
          }
        }
      };
    },
    async onResponse(context) {
      return context;
    },
    async onError(context) {
      if (context.kind === 'business') {
        console.warn('业务错误:', context.error.code, context.error.message);
      } else {
        console.error('请求失败:', context.error);
      }

      return { action: 'throw' };
    }
  }
});

触发时机

  • onRequest 在 SDK 完成默认配置合并前触发。适合动态补充请求头、超时、参数等。
  • onResponse 在 SDK 返回结果交给业务代码前触发。拿到的是 SDK 统一响应结构,适合统一改写返回内容。
  • onError 在 SDK 判定为业务错误,或者请求没有拿到可用业务响应时触发。可通过 context.kind 区分 businesstransport

默认配置和 onRequest 的分工

  • 默认配置 适合放稳定不变的值,比如 keybaseURL、统一超时、固定请求头。
  • onRequest 适合放每次调用都可能变化的逻辑,比如 traceId、临时鉴权参数、按接口动态改超时。

可以把它理解成:

text
client defaults -> onRequest -> final request

onRequest

onRequest 可以直接改写参数和单次请求选项。

ts
const client = lsData.create({
  hooks: {
    async onRequest(context) {
      return {
        ...context,
        params: {
          ...context.params,
          tenantId: 'demo'
        },
        requestOptions: {
          ...context.requestOptions,
          timeout: 30000
        }
      };
    }
  }
});

这个 hook 只作用于当前 client。

onResponse

onResponse 拿到的是 SDK 统一响应结构,因此你可以直接改写最终返回值。

ts
const client = lsData.create({
  hooks: {
    async onResponse(context) {
      if (Array.isArray(context.response.data)) {
        return {
          ...context,
          response: {
            ...context.response,
            data: context.response.data.slice(0, 20)
          }
        };
      }

      return context;
    }
  }
});

onError

默认情况下,SDK 会抛出 LoongshipApiError
如果你想改成兜底返回,也可以在 onError 里处理:

ts
const client = lsData.create({
  hooks: {
    async onError(context) {
      if (context.kind === 'business' && context.error.code === 29) {
        return {
          action: 'return',
          response: {
            code: 0,
            data: []
          }
        };
      }

      return { action: 'throw' };
    }
  }
});

传输错误适合统一日志、埋点,或者按业务需要转成兜底结果:

ts
const client = lsData.create({
  hooks: {
    async onError(context) {
      if (context.kind !== 'transport') {
        return { action: 'throw' };
      }

      console.error('transport error:', context.error);

      return {
        action: 'return',
        response: {
          code: 10000,
          data: []
        }
      };
    }
  }
});

如果你不想拦截,直接返回:

ts
{ action: 'throw' }

这时 SDK 会继续抛出原始错误。