网络请求
http 是 Oiyo 数据获取模块提供的轻量请求库,内置了配置派生、生命周期钩子、自动重试与请求中断能力。
发起第一个请求
直接使用默认实例 http 即可发起请求,无需任何前置配置。默认情况下,请求成功后只会拿到精炼后的 data。
// 默认只返回精炼后的响应体
const data = await http.request('https://api.example.com/pet/1')
如果需要状态码、响应头等完整信息,传入 raw: true:
const response = await http.request('/pet/1', { raw: true })
console.log(response.statusCode)
console.log(response.header)
console.log(response.data)
创建实例
真实项目通常不会直接用默认实例发请求,而是先用 createHttp 建立带 baseURL、超时和公共请求头等配置的公共实例。
export const api = createHttp({
baseURL: 'https://api.example.com',
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
})
之后在业务代码里使用这个实例,资源地址只写相对路径即可:
await api.request('/pet/1')
三大接口
request
请求方法通过 method 指定,请求体通过 body 传入,查询参数通过 query 传入,query 会被自动序列化。
await http.request('/pet', {
method: 'POST',
body: { name: 'kitty' },
query: { source: 'app' },
})
upload
upload 的 body 对应 formData,name 是文件对应的字段名(默认 'file'),onProgress 用于监听上传进度。
await http.upload('/upload', {
filePath: tempFilePath,
name: 'file',
body: { category: 'avatar' }, // 对应 formData
onProgress: ({ progress }) => {
console.log(`上传进度 ${progress}%`)
},
})
download
download 下载完成后可通过 tempFilePath 获取临时文件地址,onProgress 用于监听下载进度。
const { tempFilePath } = await http.download('/file/report.pdf', {
onProgress: ({ progress }) => {
console.log(`下载进度 ${progress}%`)
},
})
console.log(tempFilePath)
核心功能
派生带鉴权的实例
需要在已有实例基础上追加配置(例如登录后附带 Authorization)时,用 create 派生一个新实例。派生实例会与上层配置合并,同名钩子按层级顺序串联执行。
const authApi = api.create({
headers: { Authorization: 'Bearer xxx' },
})
// 同时带上 Content-Type 与 Authorization
await authApi.request('/pet/1')
拦截请求与响应
通过生命周期钩子在请求前后统一处理逻辑,例如注入 token、打点、统一错误提示。钩子通常声明在实例上,作用于该实例的所有请求。
const api = createHttp({
onRequest({ options, request }) {
console.log('发起请求', request)
},
onRequestError({ error }) {
console.error('请求失败', error)
},
onResponse({ response }) {
console.log('收到响应', response.statusCode)
},
onResponseError({ response }) {
console.error('响应错误', response.statusCode)
},
})
多层配置(公共 + 派生 + 单次请求)的同名钩子会串联执行,按配置层级顺序依次执行。因此公共实例上的钩子不会被派生实例覆盖,而是与其一同触发。
拓展请求配置
可以通过拓展 HttpCommonOptions 接口实现自定义的 options 属性。
// 可以放在 <srcDir> 目录中的任意 d.ts/ts 文件中。推荐放在 <srcDir>/types 目录下
declare module "@skiyee/oiyo/runtime" {
interface HttpCommonOptions {
// 自定义属性
requiresAuth?: boolean;
}
}
export {};
声明后,你将会在与 http 实例相关的 options 上拿到该属性。
const client = createHttp({
onRequest: (ctx) => {
// ctx.options.requiresAuth?: boolean
}
})
const auth = client.create({
onRequest: (ctx) => {
// ctx.options.requiresAuth?: boolean
}
})
auth.request('/request', { requiresAuth: true })
auth.upload('/upload', { requiresAuth: true })
auth.download('/download', { requiresAuth: true })
失败自动重试
在网络错误或响应命中重试状态码时,http 会自动重试。默认策略考虑了幂等性:
- 带请求体的方法(POST / PUT / DELETE / PATCH)默认不重试,其余方法重试一次。
- 主动取消不参与重试。
需要更特殊的重试时,可显式配置 retry / retryDelay / retryStatusCodes:
await http.request('/pet/1', {
retry: 3,
retryDelay: 1000,
retryStatusCodes: [500, 502, 503],
})
中断进行中的请求
通过 createHttpAborter() 创建中断信号,把 signal 传入请求,就能控制在响应前的任意时刻中断。
const aborter = createHttpAborter()
const promise = http.request('/pet/1', { signal: aborter.signal })
// 任意时刻中断
aborter.abort()
try {
await promise
}
catch (error) {
// 中断错误 error.name === 'AbortError'
}
中断会覆盖钩子阶段与请求进行中的阶段:信号触发后会立即 reject。
处理请求错误
非 2xx 响应(且未开启 ignoreResponseError)会抛出 HttpError,其中携带完整的请求上下文,便于统一处理。
try {
await http.request('/pet/999')
}
catch (e) {
const error = e as HttpError
console.log(error.request) // 请求资源
console.log(error.options) // 请求配置
console.log(error.response) // 完整响应
console.log(error.data) // 响应体
}
如果希望非 2xx 响应不抛错、由业务自行判断,可开启 ignoreResponseError: true。