封装axios二方包

262 阅读3分钟

前言

在前端项目开发中,直接使用 axios 发起网络请求虽然简单高效,但在大型项目或多项目协作中存在维护性差、重复代码多等问题。因此,二次封装axios的二方包是有必要的

功能需求

1. 统一请求配置

通过封装可以设置全局默认配置(如超时时间、基础路径、请求头等),避免每个项目都手动重复设置。

2. 拦截器统一管理

封装后可以集中管理请求和响应拦截器,实现通用逻辑(如错误统一处理等)

3. 接口返回格式标准化

封装可统一处理响应数据结构,确保所有接口返回的数据格式一致,便于业务层消费

4. 支持多个项目的复用

将封装后的工具打包插件,可在多个项目中复用,减少重复开发工作。

5. 增强可维护性和扩展性

当需要升级功能或者变更统一逻辑时,只需修改封装层,无需改动业务代码,降低耦合度。

6. 统一错误处理机制

可在封装中统一处理网络异常、业务错误码(如 401、500),并提供友好提示或自动重试机制。

7. 提升开发体验

封装后对外暴露简洁的 API,如 getpost 方法,让开发者更专注于业务逻辑而非底层请求细节。

功能设计

1.类接口设计

封装一个接口类,包含一个构造函数constructor(options: RequestClientOptions = {})

初始化Axios实例时可以传入一些配置参数,比如timeout超时时间、baseUrl,或是拦截器等

2.主要成员变量
instanceAxiosInstanceAxios实例
addRequestInterceptorFunction自定义添加的请求拦截
addResponseInterceptorFunction自定义添加的相应拦截
requestConfig记录config配置
downloadFunction通过一个单独的类生成文件下载方法
uploadFunction通过一个单独的类生成文件上传方法
loadingboolean记录是否需要展示loading加载状态
3.默认的全局配置

在constructor中有个defaultConfig以便不用过多配置,如下

class RequestClient {
    constructor(options: RequestClientOptions = {}) {
        const defaultConfig: RequestClientOptions = {
          headers: {
            'Content-Type': 'application/json;charset=utf-8',
          },
          responseReturn: 'raw',
          // 默认超时时间
          timeout: 10000,
        };
    }
}
4.请求参数处理

初始化对axios的配置参数paramsSerializer做处理,支持自定义参数序列化方式,也可以使用默认值

5.默认的全局拦截

在内部会定义默认的全局请求拦截和响应拦截,譬如处理请求时的页面加载loading,处理通用场景下异常status:403,500等状态码异常错误提示等(支持配置)

6.通用请求工具函数

封装通用请求工具函数request,并支持自定义或默认响应泛型供用户消费,并根据request进一步封装get,post,delete,put/patch供使用

type ResponseType<T = any> = {
    data: T
    code: number
    message: string
}
type RequestMethods = Extract<
  Method,
  'get' | 'post' | 'put' | 'delete' | 'patch' | 'option' | 'head'
>

public async request<T = ResponseType>(
    method: RequestMethods
    url: string,
    config: RequestClientConfig,
): Promise<AxiosResponse<T>> {
...
}
7.取消请求

部分场景下存在接口需主动取消请求,如tab切换过程中存在接口未响应的,在切换后不需要请求时取消请求,避免存在接口排队的情况

类设计图

classDiagram
    class RequestClient {
        +_instance: AxiosInstance
        +_clientConfig: RequestClientOptions
        +_interceptorsConfig: InterceptorsConfig<number[]>
        +addRequestInterceptor: Function
        +addResponseInterceptor: Function
        +upload: Function
        +download: Function
        +downloadByPost: Function
        +downloadByBlob: Function
        +downloadByBlobPost: Function
        +requestControllers: Map<string, AbortController>
     
        +request(method, url, config?: RequestClientConfig): Promise
        +get(url, config?: RequestClientConfig): Promise
        +post(url, data?, config?: RequestClientConfig): Promise
        +put(url, data?, config?: RequestClientConfig): Promise
        +patch(url, data?, config?: RequestClientConfig): Promise
        +delete(url, param?, config?: RequestClientConfig): Promise
        +initSuccessCodes(successCodes: number | number[] | undefined | null): Array
        +initRequestInterceptor(): void
        +initResponseInterceptor(): void
        +addRequestController(key): void
        +removeRequestController(key): void
        +cancelRequest(key, message?): void
        +cancelAllRequests(message?): void
    }

    class FileDownloader {
        +client: RequestClient
        +notification: NotificationConfig
        +message: MessageConfig
        
        +download(url, config): Promise
        +downloadByPost(url, data, config): Promise
        +downloadByBlob(url, config): Promise
        +downloadByBlobPost(url, data, config): Promise
    }

    class FileUploader {
        +client: RequestClient
        
        +upload(url, data, config)?: Promise
    }

    class Interceptormanager {
        +instance: AxiosInstance
        
        +addRequestInterceptor() RequestInterceptorConfig
        +addResponseInterceptor() ResponseInterceptorConfig
    }

    RequestClient --> FileDownloader : 依赖
    RequestClient --> FileUploader  : 依赖
    RequestClient --> Interceptormanager : 依赖
使用设计
  1. 实例初始化
// 使用默认
const  http = new RequestClient()
// 添加配置项
const  http = new RequestClient(
    config: RequestClientOptions
)

2.自定义config配置

首先config的类型是RequestClientOptions,他继承自AxiosRequestConfig,并在其基础上增加了一些其他的配置属性,譬如paramsSerializer指定序列化,interceptors初始化时指定业务的自定义拦截器等

或是初始化完成之后通过调用实例中的addRequestIntercepter或addResponseIntercepter去给axios实例的interceptors添加拦截器处理

  1. 业务代码使用
// api接口,如module=user
const http = new RequestClient()
// 1. 直接使用request方法
const _userInfo = (params) => {
    return  http.request<ResponseType>('get', url, {params})
}
// 2.使用具体的方法
const _userInfo = (params) => {
    return  http.get<ResponseType>( url, {params})
}

这里的DataType是接口返回的data中数据类型,方便提示

调用流程图

image.png