Skip to content

request ​

基础请求方法,支持流式请求、缓存、请求前转换、响应数据转换等功能。

示例 ​

ts
import { setBaseToolsConfig, request } from '@base-web-kits/base-tools-uni';
import type { RequestConfig, RequestTask, SSEMessage } from '@base-web-kits/base-tools-uni';

// 1. 在入口文件完成配置 (登录过期能够触发重新登录,log有日志输出)
setBaseToolsConfig({
  pathLogin: PAGE_LOGIN,
  log(level, data) {
    if (level === 'error') {
      sendLog('error', data); // 错误日志
    } else if (data.name === 'request') {
      sendLog('request', data); // 请求日志
    } else {
      sendLog('xx', data); // 其他日志
    }
  },
});

// 2. 封装项目的基础请求
const HOST = 'https://api.example.com';

export function requestApi<T>(config: RequestConfig) {
  return request<T>({
    header: { token: 'xx', version: 'xx', tid: 'xx' }, // 会自动过滤空值
    // transformRequest: ({ header, data }) => ({ header, data }), // 请求前转换, 如加密请求头和请求参数 (可选)
    // transformResponse: (res) => res, // 响应数据的转换, 如解密操作 (可选)
    resKey: 'data',
    msgKey: 'message',
    codeKey: 'status',
    successCode: [1],
    reloginCode: [-10],
    ...config,
    url: `${HOST}${config.url}`,
  });
}

// 3. 基于上面 requestApi 普通接口请求

type GoodItem = { id: number; name: string };

// 方式一:直接传参
export function apiGoodList(data: { page: number; size: number }) {
  return requestApi<GoodItem[]>({ url: '/goods/list', data, resKey: 'data.list' });
}

// 方式二:参数泛型写法
export function apiGoodList(config: RequestConfig<{ page: number; size: number }>) {
  return requestApi<GoodItem[]>({
    url: '/goods/list',
    resKey: 'data.list',
    ...config,
  });
}

// 调用
const goodList = await apiGoodList({ data: { page: 1, size: 10 } });

// 4. 基于上面 requestApi 流式请求 (SSE)
export function apiChatStream(config: RequestConfig<ChatData>) {
  return requestApi({
    ...config,
    url: '/sse/chatStream',
    resKey: false,
    showLoading: false,
    enableChunked: true, // 开启分块传输
  });
}

// 发送的消息类型
type ChatData = { content: string; conversationId: number };

// 可选:需要取消或提前结束时保存任务;只接收消息可省略 onTaskReady。
let chatTask: RequestTask | undefined;
const onTaskReady = (task: RequestTask) => {
  chatTask = task;
};

// 流式监听
const onMessage = (msg: SSEMessage) => {
  console.log(msg);
  // 消息处理异常只记录错误,不自动断流;需要终止时由项目显式调用 fail。
  // 可选:当确认业务结束、希望提前关闭连接时,可调用 chatTask?.complete()。
  // 可选:当确认业务失败时、希望提前关闭连接时,可调用 chatTask?.fail(error, businessCode)。
  // 不调用也可以,默认等服务端关闭连接即可。

  // 思考中
  // if (msg.type === 'thinking') { }

  // 各种消息类型
  // if (msg.type === 'xx') {  }
};

// 流式发起
const data = { content: '你好', conversationId: 123 };
apiChatStream({ data, onTaskReady, onMessage });

// 流式取消 (在组件销毁或页面关闭时调用)
chatTask?.abort();

RequestConfig ​

RequestConfig 继承自 Omit<UniApp.RequestOptions, 'success' | 'fail' | 'complete'>,额外包含以下属性:

  • resKey: string | false - 接口返回响应数据的字段, 支持"a[0].b.c"的格式, 当配置false时返回完整的响应数据
  • msgKey: string - 接口返回响应消息的字段, 支持"a[0].b.c"的格式
  • codeKey: string - 接口返回响应状态码的字段, 支持"a[0].b.c"的格式
  • successKey?: string - 接口返回成功状态码的字段, 支持"a[0].b.c"的格式 (默认取 codeKey)
  • successCode: (number | string)[] - 成功状态码列表
  • reloginCode: (number | string)[] - 登录过期状态码列表
  • transformRequest?: (ctx: { url: string; method?: string; header: Record<string, string | number | boolean>; data?: D }) => Partial<{ url: string; header: Record<string, string | number | boolean>; data?: D }> | Promise<...> - 请求前的数据转换, 可用于加密 header、data 或重写 url
  • transformResponse?: (data: any) => any - 响应数据的转换, 如解密操作
  • showLoading?: boolean | string - 是否显示进度条,默认 true,支持字符串自定义文案
  • toastError?: boolean - 是否提示接口异常,默认 true
  • cacheTime?: number - 缓存时间,默认 0 不缓存 (单位毫秒)
  • logExtra?: Record<string, unknown> - 额外输出的日志数据
  • onTaskReady?: (task: RequestTask) => void - 可选;普通和流式请求使用同一任务类型,支持取消及流式控制
  • onMessage?: MessageCallback - 接收解析后的 SSE 消息
  • responseType?: 'text' | 'arraybuffer' - 原生请求在 enableChunked: true 且未指定时,自动使用 'arraybuffer';显式配置优先,普通请求沿用宿主默认值。H5 流式路径直接读取 Fetch 字节流,无需配置此项。

返回值 ​

RequestTask 保留 UniApp.RequestTask 的原生能力,并提供 complete()、fail(error, businessCode?) 以控制流式请求。普通请求调用这两个方法时无效果。

统一返回 Promise<T>,默认 T = unknown,不根据 enableChunked 区分返回类型。普通请求的 T 由调用方声明;接口可能返回 null 时,应将其包含在 T 中。流式内容通过 onMessage 交付,工具不自动累积消息,正常完成时兑现值为 undefined;调用方只等待结束、处理失败,不读取结果,也不需要指定 T。即使为流式请求指定了 T,工具也不会生成该类型的结果。普通和流式请求统一使用 RequestTask。

请求日志(2.0.0) ​

继续通过 setBaseToolsConfig({ log }) 接收请求结束日志,成功和失败均记录,不再提供单次调用关闭日志的开关。普通 HTTP 调用在业务结果判断及结果提取完成后输出一次结束日志;日志和 UI 回调的同步异常、异步拒绝不覆盖已确定的请求结果。

字段含义 ​

data 自动保存 transformRequest 执行前的独立参数快照;url/header/method 记录实际请求值,原生与 H5 路径保持一致。二次封装应先补齐公共业务参数,再调用 request,将加密、编码等传输转换放入 transformRequest。转换内部新增或修改的参数不进入 data 日志,转换抛错时仍保留转换前快照;缓存键继续使用实际发送参数。

保留 name、status、url、method、data、header、res、e、fromCache 和 logExtra。res 通常是执行 transformResponse 后、按 resKey 提取业务结果前的完整正文;若 transformResponse 抛错,则保留宿主传入转换函数的正文。e 中的 Error 转换为包含 name/message/stack 的普通对象,并递归记录标准 Error.cause;循环的 Error.cause 用 [Circular error cause] 截断,非 Error 值保持原值。reject 仍传递原始异常,不使用日志序列化结果。

开启 toastError 时,普通响应处理异常使用 Error.message 生成“请求失败: 错误信息”提示,不将 cause 或响应正文展示给用户。封装库可抛出 new Error('响应处理失败', { cause: originalError }),分别提供用户提示和日志中的原始原因;工具库不根据提示文字或异常类型推断业务专有分类。

字段类型说明
successboolean按现有 successCode/successKey 等规则处理成功,且完成结果提取;业务失败、掉登或处理异常为 false
businessCodestring | number,可选从转换后的响应按 codeKey 读取,不等同于 successKey,也不保证是未经转换的服务端原码
httpStatusnumber,可选实际收到的 HTTP 状态,独立于业务结果
responseHeaderRecord<string, unknown>,可选实际取得的响应头;Web 受浏览器权限限制,uni 以宿主提供的值为准
failureStageRequestFailureStage,可选prepare、network、http、response、business
failureCodeRequestFailureCode 或扩展字符串,可选明确取得的失败原因,见下表
networkStartTimeMs / networkEndTimeMsnumber,可选实际发送前、正文接收完成或传输失败通知时的 Unix 毫秒时间戳
networkStartTime / networkEndTimestring,可选网络开始、结束时间,格式 YYYY-MM-DD HH:mm:ss.SSS,使用运行环境时区
networkDurationMsnumber,可选网络耗时,毫秒,优先使用单调时钟,可含小数,不保证等于时间戳差

工具库只提供网络计时,不采集请求总耗时或调用方上下文。调用方自定义字段通过 logExtra 传入,工具库不规定其名称或结构。缓存命中、发送前失败时不生成网络计时字段。

Error 及其 cause 序列化时保留实际存在的字符串或数字 code;请求 failureCode 与异常 code 相互独立。

status 仍表示调用状态,不等同于 success。例如 HTTP 已返回但业务码表示掉登时,仍可能输出 level: 'info'、status: 'success',同时 success: false、failureStage: 'business'、failureCode: 'login_required'。HTTP 200 不代表业务成功;HTTP 非 2xx 返回可解析业务正文时,仍沿用已有业务判断规则。

失败分类 ​

failureStagefailureCode含义
preparerequest_prepare_failed参数过滤、请求转换或编码等准备步骤失败
networknetwork_failed网络调用或正文接收失败
networktimeout / aborted明确确认的超时或取消
httphttp_failedHTTP 错误响应无法按原有流程处理
responseresponse_transform_failedtransformResponse 同步抛错
responseresponse_result_failed业务字段读取或结果提取失败
businessbusiness_failed / login_required按既有规则判定业务拒绝或登录失效

RequestFailureCode 还包含 response_parse_failed,供能够明确识别解析错误的封装使用;工具库不会根据某个码值推断解析失败。普通成功日志不主动添加失败字段。已取得的 HTTP 状态、响应头和传输时间,在后续响应处理失败时仍保留。

附加字段与 getter ​

logExtra.url 可整值覆盖日志地址;header 按名称大小写不敏感浅合并,data/res 的普通对象递归合并,数组和其他值整体替换,根值 undefined 不覆盖。补丁只作用于日志副本,不改变实际请求、业务返回或缓存;没有实际响应时不凭补丁生成 res。method、success、失败分类等公共结果字段不可覆盖。调用方可使用可枚举 getter 延迟生成自己的附加字段;工具库在结果确定后读取一次。需要测量封装耗时时,可结合 startTimer 使用:

ts
const logExtra = {
  get completedAtMs() {
    return Date.now();
  },
  tag: 'example',
};

await requestApi({ url: '/items', logExtra });
// completedAtMs 在结束日志组装时读取,而不是在创建对象时读取。

避免在请求完成前提前展开或序列化 logExtra;未配置 log 时,工具库不读取这些 getter。

版本 ​

2.0.0 升级说明 ​

网络计时字段统一增加 network 前缀,耗时字段明确使用毫秒单位;以下旧字段不再由工具库生成,日志接收方需同步调整:

旧字段2.0.0 字段
startTimenetworkStartTime
endTimenetworkEndTime
startTimeMsnetworkStartTimeMs
endTimeMsnetworkEndTimeMs
durationnetworkDurationMs

同时,日志中的 Error 及其 cause 新增保留字符串或数字 code。请求调用方式及 logExtra 扩展方式保持不变。

历史版本 ​

  • 1.7.0 增强普通 HTTP 结束日志,新增业务结果、HTTP 信息和失败分类;时间字段改为传输口径,详见升级说明。
  • 1.0.2 新增