@done-coding/request-base
是一个请求库的基础包,提供了统一的请求配置接口和响应数据结构。本包主要关注于业务层面的请求处理,而不是底层网络请求的实现。
不建议直接使用本包,而是根据具体场景使用对应的细化包:
- 在 uni-app 项目中使用 @done-coding/request-uni
- 在 axios 项目中使用 @done-coding/request-axios
- 在 ofetch 项目中使用 @done-coding/request-ofetch
这些细化包已经基于本包进行了完整的封装,提供了更好的类型支持和更简单的使用方式。直接使用本包需要自行处理很多细节,建议使用对应的场景化包。
如果以上场景化包不再满足需求,可以使用本包进行自定义封装,例如:
- 需要支持其他请求库(如 fetch、XMLHttpRequest 等)
- 需要特殊的请求处理逻辑
- 需要自定义的响应处理方式
本包采用间接测试策略,通过各细化包的实际应用来验证功能的正确性:
- 各细化包(axios、ofetch、uni)的应用本身就是对 base 包最完整的集成测试
- 每个细化包都有其专门的单元测试,这些测试覆盖了:
- 基于 base 包的功能实现
- 特定场景下的功能验证
- 边界条件和错误处理
- 类型定义和类型推导
- 通过这种方式,base 包的功能得到了更实际和全面的验证
- 🔄 统一的请求处理流程:无论使用哪种请求客户端,都保证相同的请求处理流程
- 📦 统一的数据结构:所有请求响应都会被统一处理,确保进入 then 的数据结构一致
- ✅ 自动的状态码处理:自动处理业务状态码,只有在成功状态下才会进入 then
- 🛡️ 统一的错误处理:所有错误都会被统一捕获和处理,进入 catch 的错误都是经过处理的
- 🔍 可预测的结果:保证请求结果的可预测性,减少重复的状态码判断
- 🔄 请求重试机制:支持请求失败后的自动重试
- 🧠 缓存支持:内置缓存机制,支持自定义缓存策略
- 🐛 调试支持:内置调试功能,支持详细的请求生命周期日志
所有基于此包扩展的子包都保证:
- 统一的请求处理流程
- 一致的数据结构返回
- 自动的状态码处理
- 统一的错误处理机制
- 可预测的请求结果
可用的实现:
- @done-coding/request-axios - 基于 axios 的请求拦截器实现
- @done-coding/request-ofetch - 基于 ofetch 的请求拦截器实现
- @done-coding/request-uni - 基于 uni-app 的请求拦截器实现
# 使用 npm
npm install @done-coding/request-base
# 使用 yarn
yarn add @done-coding/request-base
# 使用 pnpm
pnpm add @done-coding/request-base
本包支持全局配置和请求时配置,并且有默认策略和合并策略:
issue
是base包最核心的配置项,它定义了如何发起实际的网络请求。这个函数需要实现具体的请求逻辑,并返回统一格式的响应。
const request = createRequest({
basePath: 'https://api.example.com',
// 核心配置:如何发起请求
issue: async <D>(config: IssueConfig<C>, extendConfig: ExtendConfig) => {
// config 包含请求配置
// - url: 请求地址
// - method: 请求方法
// - data: 请求数据
// - headers: 请求头
// - BASE_PATH: 基础路径(由basePath生成)
// - TIMEOUT: 超时时间(由timeout生成)
// - DEBUG: 是否开启调试
// - ... 其他自定义配置
// extendConfig 包含扩展配置
// - uiConfig: UI相关配置
// - errorToast: 是否显示错误提示
// - cacheConfig: 缓存相关配置
// - useCache: 是否使用缓存
// 返回统一格式的响应
return {
code: number | string, // 业务状态码
data: D, // 业务数据(泛型类型)
message: string // 业务消息
};
}
});
issue 函数的特点:
- 必选配置:必须提供此配置才能创建请求实例
- 统一响应格式:必须返回统一格式的响应对象(RequestResult)
- 完整配置信息:可以访问所有请求相关的配置
- 灵活实现:可以根据需要实现任何请求库的调用
- 错误处理:如果请求过程中发生错误,会被自动捕获并转换为统一的错误格式
- 类型安全:支持泛型类型,可以指定返回数据的类型
issue 函数的错误处理:
- 如果请求过程中发生错误,会被自动转换为 RequestFailResult 类型
- 网络错误会被转换为 RequestFailResultNetwork
- 业务错误会被转换为 RequestFailResultBusiness
- 可以通过 beforeError 配置来自定义错误处理逻辑
在创建请求实例时配置,会应用到所有请求:
const request = createRequest({
basePath: 'https://api.example.com',
timeout: 5000,
headers: {
'Content-Type': 'application/json'
},
// 其他全局配置...
});
在发起请求时配置,只会应用到当前请求:
const response = await request({
url: '/api/data',
method: 'GET',
timeout: 3000, // 覆盖全局配置
headers: {
'Authorization': 'Bearer token' // 合并到全局配置
}
});
部分配置项有默认值:
-
timeout
: 默认 1000ms -
beforeRequest
: 默认返回原始配置 -
isSuccessNetworkCode
: 默认判断 code >= 200 && code < 300 -
uiConfig.errorToast
: 默认 true
配置的合并遵循以下规则:
- 请求配置:请求时配置会覆盖全局配置
- headers:请求时的 headers 会与全局 headers 合并
- 拦截器:拦截器会按顺序执行,全局拦截器先执行
- UI配置:请求时的 UI 配置会覆盖全局 UI 配置
- 缓存配置:请求时的缓存配置会覆盖全局缓存配置
缓存配置支持全局和请求级别,并且可以自定义缓存策略:
const request = createRequest({
basePath: 'https://api.example.com',
cacheConfig: {
// 生成缓存键
getKey: (config) => `${config.url}-${JSON.stringify(config.params)}`,
// 设置缓存
setCache: async (key, data, config) => {
// 实现缓存存储逻辑
// 只有在业务成功时才会调用
},
// 获取缓存
getCache: async (key) => {
// 实现缓存获取逻辑
return undefined;
}
},
// 默认启用缓存
useCache: true
});
const response = await request({
url: '/api/data',
method: 'GET',
// 覆盖全局缓存配置
cacheConfig: {
useCache: false // 禁用当前请求的缓存
}
});
import { createRequest } from '@done-coding/request-base';
const request = createRequest({
basePath: 'https://api.example.com',
// 缓存配置
cacheConfig: {
useCache: true
},
// 缓存选项配置
cache: {
getKey: (config) => `${config.url}-${JSON.stringify(config.params)}`,
setCache: async (key, data) => {
// 实现缓存存储逻辑
},
getCache: async (key) => {
// 实现缓存获取逻辑
return undefined;
}
}
});
// 使用缓存
const response = await request({
url: '/api/data',
method: 'GET',
cacheConfig: {
useCache: true
}
});
-
缓存配置:
-
cacheConfig
: 控制是否使用缓存-
useCache
: 是否启用缓存
-
-
cache
: 缓存的具体实现-
getKey
: 生成缓存键 -
setCache
: 存储缓存 -
getCache
: 获取缓存
-
-
-
缓存键生成:
- 通过
cache.getKey
函数生成缓存键 - 默认使用 URL 和参数组合生成
- 支持自定义生成策略
- 通过
-
缓存存储:
- 通过
cache.setCache
函数存储缓存 - 只有在业务成功时才会调用
- 支持异步存储操作
- 通过
-
缓存获取:
- 通过
cache.getCache
函数获取缓存 - 支持异步获取操作
- 返回 undefined 表示无缓存
- 通过
-
缓存控制:
- 通过
cacheConfig.useCache
控制是否使用缓存 - 支持全局和请求级别控制
- 请求级别配置优先级高于全局配置
- 通过
创建一个请求实例。
function createRequest(options: Options): RequestFunction;
-
options
: 请求配置选项-
basePath
: 基础URL -
timeout
: 超时时间 -
headers
: 请求头 -
beforeRequest
: 请求拦截器 -
beforeResponse
: 响应拦截器 -
beforeError
: 错误拦截器 -
uiConfig
: UI交互配置 -
cacheConfig
: 缓存配置
-
返回一个请求函数,可以用于发起请求。
import { createRequest } from '@done-coding/request-base';
const request = createRequest({
basePath: 'https://api.example.com',
timeout: 5000,
headers: {
'Content-Type': 'application/json'
}
});
// 发起请求
const response = await request({
url: '/api/data',
method: 'GET',
params: { id: 1 }
});
import { createRequest } from '@done-coding/request-base';
const request = createRequest({
basePath: 'https://api.example.com',
beforeError: (error) => {
if (error.isBusinessError) {
// 处理业务错误
return {
newError: error,
canShowErrorToast: true
};
}
// 处理网络错误
return {
newError: error,
canShowErrorToast: true
};
}
});
try {
const response = await request({
url: '/api/data',
method: 'GET'
});
} catch (error) {
// 错误已经被 beforeError 处理
console.error(error);
}
import { createRequest } from '@done-coding/request-base';
const request = createRequest({
basePath: 'https://api.example.com',
// 缓存配置
cacheConfig: {
useCache: true
},
// 缓存选项配置
cache: {
getKey: (config) => `${config.url}-${JSON.stringify(config.params)}`,
setCache: async (key, data) => {
// 实现缓存存储逻辑
},
getCache: async (key) => {
// 实现缓存获取逻辑
return undefined;
}
}
});
// 使用缓存
const response = await request({
url: '/api/data',
method: 'GET',
cacheConfig: {
useCache: true
}
});
- 使用
beforeError
统一处理错误 - 区分业务错误和网络错误
- 根据错误类型显示不同的提示信息
- 在请求前统一处理请求配置
- 添加通用请求头
- 处理请求参数
- 统一处理响应数据
- 转换响应格式
- 处理特殊响应
- 合理设置缓存键
- 控制缓存生命周期
- 及时清理过期缓存
# 安装依赖
pnpm install
# 开发模式运行
pnpm dev
# 构建
pnpm build
# 测试
pnpm test
MIT