我是如何用vue3+typeScript封装一个axios类工具,来降低代码的耦合度,方便后期的维护与开发

201 阅读5分钟

我们在日常使用axios时都是直接使用axios.request(config)来发送请求和instance.interceptors.request.use()来进行响应拦截,

但是如果后期axios这个项目不再维护了,或者我们要换成别的网络请求方式了。这样又怎么办呢?难道我们要一处一处的起修改我们的代码吗?重构我们的请求模块?

这样不仅会给我们带来大量的工作量,而且代码的耦合度太高也会导致代码如果出现bug。 但是如果我们把axios在进行封装,封装出一个axios类,然后只让实例依赖axios,我们要发送请求时就使用我们自己封装的axios类,这样我们在后期要换成其他的网络请求方式时,就只修改我们封装的axios类就可以了。这样既可以降低代码的耦合度,也可以降低我们后期维护代码的工作量

版本

b43d45bc67fcc01f5d19d6d644cf054.png

文件目录结果

在这里插入图片描述

封装

  1. 首先我们先声明我们的要使用的参数类型来满足我们的typeScript规则,创建一个types.ts文件来存放我们的代码
// 导入axios里面定义的两个类型AxiosRequestConfig(axios参数传入类型), AxiosResponse(请求类型)
import type { AxiosRequestConfig, AxiosResponse } from 'axios'

// 定义一个ZYRequestInterceptors接口用于增加我们传入的AxiosRequestConfig的请求拦截的类型
export interface ZYRequestInterceptors<T = AxiosResponse> {
  // 请求成功
  requestInterceptor?: (config: AxiosRequestConfig) => AxiosRequestConfig
  // 请求失败
  requestInterceptorCatch?: (error: any) => any
  // 响应成功
  responseInterceptor?: (res: T) => T
  // 响应失败
  responseInterceptorCatch?: (error: any) => any
}
// 导出ZYRequestConfig给index的ZYRequest类的constructor构造类传入参数是设置传参类型,
// ZYRequestConfig继承AxiosRequestConfig并且包含ZYRequestInterceptors,所以具有AxiosRequestConfig和ZYRequestInterceptors的功能
export interface ZYRequestConfig<T = AxiosResponse> extends AxiosRequestConfig {
  interceptors?: ZYRequestInterceptors<T>
}

  • 我们先导入axios里面定义的两个类型AxiosRequestConfig(axios参数传入类型),和 AxiosResponse(请求类型)。
  • 然后定义一个ZYRequestInterceptors接口用于增加我们传入的AxiosRequestConfig的请求拦截的类型
    • 当请求成功时的类型定义requestInterceptor
    • 请求失败时的类型定义requestInterceptorCatch
    • 响应成功时的类型定义responseInterceptor
    • 响应失败时的类型定义responseInterceptorCatch
  • 最后我们导出ZYRequestConfig给index的ZYRequest类的constructor构造类传入参数是设置传参类型,
  • ZYRequestConfig继承AxiosRequestConfig并且包含ZYRequestInterceptors,所以具有AxiosRequestConfig和ZYRequestInterceptors的功能

封装我们自己的axios类,创建一个index.ts文件来存放我们的代码

//首先先导入我们的axios
import axios from 'axios'
//然后导入我们的axios里面定义的AxiosInstance
import type { AxiosInstance } from 'axios'
// 导入自己定义的两个类型
import type { ZYRequestInterceptors, ZYRequestConfig } from './type'

// 定义一个ZYRequest 类用于发送axion的请求
class ZYRequest {
  // 定义一个axion实例属性
  instance: AxiosInstance
  // 定义一个拦截器属性
  interceptors?: ZYRequestInterceptors

  // 利用构造函数要求传入使用 ZYRequest类时传入参数

  constructor(config: ZYRequestConfig) {
    // 把axios实例赋给instance
    this.instance = axios.create(config)


    // 把传入的拦截器赋值给interceptors
    this.interceptors = config.interceptors
    // 请求拦截
    this.instance.interceptors.request.use(
      this.interceptors?.requestInterceptor,
      this.interceptors?.requestInterceptorCatch
    )
    // 响应拦截
    this.instance.interceptors.response.use(
      this.interceptors?.responseInterceptor,
      this.interceptors?.responseInterceptorCatch
    )
    // 2.添加所有的实例都有的拦截器
    // 请求拦截
    this.instance.interceptors.request.use(
      (config) => {
        // console.log('所有的实例都有的拦截器: 请求成功拦截')
        return config
      },
      (err) => {
        console.log('所有的实例都有的拦截器: 请求失败拦截')
        return err
      }
    )
    // 响应拦截
    this.instance.interceptors.response.use(
      (res) => {
        // console.log('所有的实例都有的拦截器: 响应成功拦截'
        const data = res.data
        // 对返回的响应返回值进行判断,是否响应成功
        if (data.returnCode === '-1001') {
          console.log('请求失败~, 错误信息')
        } else {
          return data
        }
      },
      (err) => {
        console.log('所有的实例都有的拦截器: 响应失败拦截')
      
        // 例子: 判断不同的HttpErrorCode显示不同的错误信息
        if (err.response.status === 404) {
          console.log('404的错误~')
        }
        return err
      }
    )
  }
  request<T = any>(config: ZYRequestConfig<T>): Promise<T> {
    return new Promise((resolve, reject) => {
      // 1.单个请求对请求config的处理
      if (config.interceptors?.requestInterceptor) {
        config = config.interceptors.requestInterceptor(config)
      }

      this.instance
        .request<any, T>(config)
        .then((res) => {
          // 1.单个请求对数据的处理
          if (config.interceptors?.responseInterceptor) {
            res = config.interceptors.responseInterceptor(res)
          }
          // 将结果resolve返回出去
          resolve(res)
        })
        .catch((err: any) => {
          reject(err)
          return err
        })
    })
  }
  // 定义发送请求的ts类型
  get<T = any>(config: ZYRequestConfig<T>): Promise<T> {
    return this.request<T>({ ...config, method: 'GET' })
  }

  post<T = any>(config: ZYRequestConfig<T>): Promise<T> {
    return this.request<T>({ ...config, method: 'POST' })
  }

  delete<T = any>(config: ZYRequestConfig<T>): Promise<T> {
    return this.request<T>({ ...config, method: 'DELETE' })
  }

  patch<T = any>(config: ZYRequestConfig<T>): Promise<T> {
    return this.request<T>({ ...config, method: 'PATCH' })
  }
}
export default ZYRequest

  • 首先先导入我们的axios
  • 然后然导入我们的axios里面定义的AxiosInstance,和自己定义的两个类型 ZYRequestInterceptors, ZYRequestConfig
  • 然后我们定义一个ZYRequest类,用于定义我们要发送axion的请求的类
  • 然后我们在ZYRequest类里面一个axion实例属性和一个拦截器属性,以防创建多个实例时数据交叉修改,以至于出现bug。
  • 然后我们利用构造函数要求我们在使用我们当前这个axios实例时,要求要传入参数,参数类型ZYRequestConfig
  • 在构造函数里把axios实例赋给instance,以及把传入的拦截器赋值给interceptors,使用.use把我们接受的请求拦截、响应拦截函数挂载在我们的真实的axios实例上,但是这些拦截只针对于我们创建的实例并不是全局请求。
  • 所以我们应该再创建一个全局的响应拦截和请求拦截,这个拦截将添加到所有的请求实例中,以及我们要编写对于的错误处理机制,以增强我们的代码的健壮性
  • 最后我们要编写我们的request和get、post、delete、patch请求方法。对单个请求对请求的config进行处理

写在最后

伙伴们,如果你觉得我写的文章对你有帮助就给zayyo点一个赞👍或者关注➕都是对我最大的支持。当然你也可以加我微信:IsZhangjianhao,邀你进我的前端学习交流群,一起学习前端,成为更优秀的工程师~

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 29 天,点击查看活动详情