Axios 简单封装
Axios 简单封装
封装
type ErrMsg = string
type Result<T> = [ErrMsg | null, T | null, any?]
type PromiseResult<T> = Promise<Result<T>>import Axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, Canceler, AxiosError, CancelToken, CancelTokenSource } from 'axios';
// 后面将要使用的创建请求服务的配置
const serviceConfig = {
// 默认配置们
baseURL: import.meta.env.VITE_API,
timeout: 1000 * 60 * 10, // 超时时间, 毫秒
// withCredentials: true, // 发送请求时,是否带 cookie
headers: {
'Content-Type': 'application/json; charset=utf-8',
}
}
/**
* 创建一个取消请求的source
* 设置某个请求的配置 config.cancelToken = source.token
* 再调用 source.cancel() 即可取消这个请求
* @returns {CancelTokenSource}
*/
export function createCancelSource(): CancelTokenSource {
return Axios.CancelToken.source()
}
// 扩充传参,ts类型主要此处生成,所以可以写在这个文件中,且这个类型是拓展了AxiosRequestConfig
interface MyAxiosConfig extends AxiosRequestConfig {
skipHandle?: boolean, // 是跳过处理
notTip?: boolean, // 出错是否不会自动弹出提示(skipHandle 值不能为true)
skipToken?: boolean, // 不再统一添加token
}
class AxiosServer {
private instance: AxiosInstance;
constructor(config: MyAxiosConfig) {
this.instance = Axios.create(config)
// 全局请求前拦截
// this.instance.interceptors.request.use(req => req, err => err) 暂不需要,有request方法封装了
// 全局请求后拦截
// this.instance.interceptors.response.use(res => res, err => err) 暂不需要,有request方法封装了
}
// 要返回的实例
public async request<T = any>(config: MyAxiosConfig): PromiseResult<T> {
config.headers = config.headers || {}
// 如果能拿到后台返回的数据,则此对象有值
let serviceResult: AxiosResponse | null = null;
// 拿不到后台相应的数据,则此对象有值,比如网络错误、跨域报错等等
let serviceError: AxiosError | null = null;
// 统一增加Authorization请求头, skipToken 跳过增加token
const token = '' // 此处需要得到token,比如:cookies.get('token');
if (token && !config.skipToken) {
config.headers['Authorization'] = `Bearer ${token}`
}
try {
// 去发起请求
serviceResult = await this.instance.request(config)
// 只要http请求状态是200系列,就会走这里
} catch(error: any) {
serviceResult = null
console.error(error)
if (error.response) {
// 包含 response 字段,说明只是http状态码非200系列,但后台仍返回了对应的响应数据结构
// 可能是http状态码非200系列:如果服务器返回错误的状态码,400~599,会抛出一个HTTP错误(HTTP Error)。
error = error as AxiosError
serviceResult = error.response
} else {
// * 通用错误:比如JSON解析错误等,会抛出一个通用错误(General Error)。
// * 请求被前端中断:如果请求被前端中断,会抛出一个取消错误(Cancel Error)。
// * 网络错误:如果请求失败,比如网络不可用或请求超时,会抛出一个网络错误(Error)。
serviceError = error as AxiosError
}
}
// 正常会走这里,即使返回的http状态码是500,只要后台响应了数据,就会走这里
if (serviceResult) {
// 去解析后台返回的数据结构
return this.dataHandler(serviceResult, config)
} else {
// 后台没能响应数据,比如:
// * 通用错误,比如JOSN解析错误
// * 请求被前端中断
// * 网络错误、请求超时、设备未联网、后台服务未启动等等
return this.errorHandler(serviceError, config)
}
}
// 返回结果的处理程序
private async dataHandler<T = any>(axiosResponse: AxiosResponse, config: MyAxiosConfig): PromiseResult<T> {
// 不需处理,直接返回
if (config.skipHandle) return [null, null, axiosResponse]
// 后端返回的消息体,假设数据类型见下
type ResponseBody = {
code: number,
data: any,
msg: string | null,
}
const responseBody: ResponseBody | null = axiosResponse?.data || null
let errMsg = ''
// 添加返回参数的处理
// 登录过期
// if (axiosResponse?.status === 424) {
// // 刷新token后,重新再发起请求
// // await refreshToken() // 刷新token的操作
// return this.request(config)
// }
// code标记非正常,记录错误信息弹出
// if (responseBody?.code !== 0) {
// errMsg = responseBody?.msg || '服务出错'
// }
// 需要弹框
if (errMsg && !config.notTip) {
alert(errMsg)
}
return [errMsg, responseBody as T, axiosResponse]
}
// 服务出错/取消请求的处理
private errorHandler(error: AxiosError | any, config: MyAxiosConfig): Result<null> {
// 不需处理,直接返回
if (config.skipHandle) return [null, null, error]
let errMsg: ErrMsg = '服务出错!'
let isAxiosError = error?.isAxiosError || false
if (isAxiosError) {
// 是 axios 错误,只要不是代码运行错误,比如解析json错误、执行不存在的方法等等,都走这里
error = error as AxiosError
if (error?.message?.includes('timeout')) {
// 超时
let timeout = error?.config?.timeout || 0
errMsg = `请求超时 | 当前超时时间:${timeout / 1000}S` // 请求超时
} else if (error?.message?.includes('Network Error')) {
// 网络错误或者后端接口服务未启动
errMsg = '网络错误,请检查设备联网或稍后再试!'
} else if (error?.message?.includes('canceled')) {
// 接口被代码手动中断,不应提示
errMsg = ''
} else {
errMsg = error?.message || '服务出错,请稍后再试!'
}
} else {
// 通用错误,比如解析json错误、执行不存在的方法,throw 抛出的错误等等
error = error as any
errMsg = error.message || ''
}
// 需要弹框
if (errMsg && !config.notTip) {
alert(errMsg)
}
return [errMsg, null, error]
}
}
// 创建一个 axios 服务
const service = new AxiosServer(serviceConfig)
// 导出的请求方法
export const request = service.request.bind(service);使用
Last updated