@bubblesjs/request

@bubblesjs/request 是一个基于 Alova 的请求封装。它把公共请求头、响应转换、业务码判断、消息提示、缓存适配器和单次请求覆盖配置集中到一处管理。

安装

pnpm
npm
yarn
bun
pnpm add @bubblesjs/request alova

快速开始

import { createInstance } from '@bubblesjs/request'

const request = createInstance({
  baseUrl: '/api',
  commonHeaders: {
    'Content-Type': 'application/json',
    Authorization: async () => `Bearer ${await getToken()}`
  },
  successMessageFunc: (message) => toast.success(message),
  errorMessageFunc: (message) => toast.error(message),
  unAuthorizedResponseFunc: () => router.push('/login')
})

const user = await request.Get('/user/info')
const result = await request.Post('/user/update', {
  body: { name: '张三' }
})

默认情况下,成功的包裹响应形如:

{
  code: 200,
  data: { id: 1 },
  message: 'ok'
}

最终返回值是 responseDataKey 配置的字段,所以上面的响应会解析成 { id: 1 }

双重调用实例

createDualCallInstance 会返回一个默认 Alova 实例,同时这个实例也可以作为函数调用,用临时配置创建新的请求实例。

import { createDualCallInstance } from '@bubblesjs/request'

const request = createDualCallInstance({
  baseUrl: '/api',
  isShowSuccessMessage: false,
  errorMessageFunc: (message) => toast.error(message)
})

await request.Get('/user/profile')

await request({
  isShowSuccessMessage: true,
  successMessageFunc: (message) => toast.success(message)
}).Post('/user/create', {
  body: { name: '李四' }
})

配置项

参数类型默认值说明
baseUrlstring'/'传给 Alova 的 baseURL
timeoutnumberundefined请求超时时间。
commonHeadersRecord<string, HeaderValue>{}公共请求头,值可以是静态值或异步函数。
statusMapStatusMap{ success: 200, unAuthorized: 401 }HTTP 状态匹配规则。
codeMapCodeMap{ success: [200], unAuthorized: [401] }业务状态码匹配规则。
responseCodeKeystring'code'包裹响应里的业务码字段名。
responseDataKeystring'data'包裹响应里的数据字段名。
responseMessageKeystring'message'包裹响应里的消息字段名。
isWrappedbooleantrue响应是否是 { code, data, message } 这类包裹结构。
isTransformResponsebooleantrue是否在 responded.onSuccess 中转换响应。
isShowSuccessMessagebooleanfalse业务成功后是否调用 successMessageFunc
successDefaultMessagestring'操作成功'默认成功消息。
isShowErrorMessagebooleantrueHTTP、业务或网络错误时是否调用 errorMessageFunc
errorDefaultMessagestring'服务异常'默认错误消息。
successMessageFunc(message: string) => voidundefined成功消息处理函数。
errorMessageFunc(message: string) => voidundefined错误消息处理函数。
unAuthorizedResponseFunc() => voidundefinedHTTP 状态或业务码命中未授权时调用。
statesHookStatesHookundefinedAlova 的状态钩子,用于 React、Vue 等框架集成。
requestAdapterAlovaRequestAdapteradapterFetch()Alova 请求适配器。
cacheForGlobalCacheConfig | nullnullAlova 全局缓存配置。
cacheLoggerbooleantrueAlova 缓存日志开关。
l1CacheAlovaGlobalCacheAdapterundefinedAlova 一级缓存适配器。
l2CacheAlovaGlobalCacheAdapterundefinedAlova 二级缓存适配器。
storageAdapterAlovaGlobalCacheAdapterundefinedl2Cache 的兼容别名。

匹配规则

statusMap.successstatusMap.unAuthorized 支持数字、数字数组或函数:

const request = createInstance({
  statusMap: {
    success: [200, 201, 204],
    unAuthorized: (status) => status === 401 || status === 419
  }
})

codeMap.successcodeMap.unAuthorized 支持数字或字符串数组:

const request = createInstance({
  responseCodeKey: 'status',
  responseMessageKey: 'msg',
  codeMap: {
    success: [0, 'OK'],
    unAuthorized: [401, 'TOKEN_EXPIRED']
  }
})

单次请求 meta 覆盖

以下配置可以通过单个请求的 meta 覆盖:

  • isWrapped
  • isTransformResponse
  • isShowSuccessMessage
  • isShowErrorMessage
const rawResponse = await request.Get('/download/file', {
  meta: {
    isTransformResponse: false,
    isShowErrorMessage: false
  }
})

const rawUploadData = await request.Post('/upload', {
  body: formData,
  meta: {
    isWrapped: false
  }
})

响应结构

默认 fetch 适配器会返回 Response,内部会根据 content-type 解析。JSON 响应使用 json(),文本响应使用 text(),可解析的 JSON 字符串会自动转换。

同时也支持 Axios 风格和 Taro 风格的响应:

// Axios 风格
{
  status: 200,
  data: { code: 200, data: [], message: 'loaded' }
}

// Taro 风格
{
  statusCode: 200,
  data: { code: 200, data: { ok: true }, msg: 'done' }
}

对于 Taro 上传接口这类把 data 返回为 JSON 字符串的场景,会先解析字符串,再应用 codeMapresponseDataKey

自定义适配器

可以传入任意 Alova 请求适配器。如果适配器同时暴露缓存适配器,可以通过 l2CachestorageAdapter 传入。

import { createInstance } from '@bubblesjs/request'
import { adapterTaro } from '@alova/adapter-taro'

const taroAdapter = adapterTaro()

const request = createInstance({
  baseUrl: '/api',
  requestAdapter: taroAdapter.requestAdapter,
  storageAdapter: taroAdapter.storageAdapter,
  responseMessageKey: 'msg'
})

类型定义

type MaybePromise<T> = T | Promise<T>

type HeaderValue =
  | string
  | number
  | boolean
  | null
  | undefined
  | (() => MaybePromise<string | number | boolean | null | undefined>)

type StatusMatcher<RE> =
  | number
  | number[]
  | ((status: number, response: RE) => boolean)

type CodeMatcher = Array<number | string>

interface StatusMap<RE = unknown> {
  success?: StatusMatcher<RE>
  unAuthorized?: StatusMatcher<RE>
}

interface CodeMap {
  success?: CodeMatcher
  unAuthorized?: CodeMatcher
}

interface RequestMeta {
  isWrapped?: boolean
  isTransformResponse?: boolean
  isShowSuccessMessage?: boolean
  isShowErrorMessage?: boolean
}