使用typescript+element-plus对axios进行封装

128 阅读2分钟

实现功能

  1. 自定义hooks处理请求/响应拦截
  2. 实现接口定义
  3. axios api进行封装

版本依赖

"dependencies": {
    "axios": "^0.26.1",
    "element-plus": "^2.1.8",
    "vue": "^3.0.0",
},

代码实现

    // src/service/request/config.ts
    // 对基础条件进行配置
    let BASE_URL = 'http://123.207.32.32:8000/'
    const TIME_OUT = 10000
    if (process.env.NODE_ENV === 'development') {
      BASE_URL = 'http://123.207.32.32:8000/'
    } else if (process.env.NODE_ENV === 'production') {
      BASE_URL = 'http://123.207.32.32:8000/'
    } else {
      BASE_URL = 'http://123.207.32.32:8000/'
    }
    export { BASE_URL, TIME_OUT }
   // src/service/request/type.ts
   // 定义interface接口
   import { AxiosRequestConfig, AxiosResponse } from 'axios'
   interface ZRequestInterceptors {
      requestInterceptor?: (config: AxiosRequestConfig) => AxiosRequestConfig
      requestInterceptorCatcher?: (error: any) => any
      // 因为我们在全局响应拦截器里面对数据进行了处理const data = res.data 会导致res的数据类型不再是AxiosResponse 这里暂时改为any
      // responseInterceptor?: (res: AxiosResponse) => AxiosResponse
      responseInterceptor?: (res: any) => any
      responseInterceptorCatcher?: (error: any) => any
    }
    interface ZRequestConfig extends AxiosRequestConfig {
      // 自定义AxiosRequestConfig类型
      interceptors?: ZRequestInterceptors // 约束用户传递的数据类型
      showLoading?: boolean // 是否展示加载loading
    }
    export { ZRequestConfig, ZRequestInterceptors }

// src/service/request/index.ts
// 实现axios封装
import axios from 'axios'
import type { AxiosInstance } from 'axios'
import { ElLoading } from 'element-plus'
import type { ZRequestInterceptors, ZRequestConfig } from './type'
import { LoadingInstance } from 'element-plus/es/components/loading/src/loading'
// import 'element-plus/es/components/loading/style/css'

export default class ZRequest {
  instance: AxiosInstance
  interceptors?: ZRequestInterceptors
  showLoading: boolean
  loading?: LoadingInstance
  constructor(config: ZRequestConfig) {
    // config 传进来的配置对象
    this.instance = axios.create(config) // 创建axios实例
    // 保存基本信息
    this.interceptors = config.interceptors // 获取用户传递的拦截器钩子
    this.showLoading = true // 默认为true
    // 从config中取出coder传入的 封装局部拦截器
    this.instance.interceptors.request.use(
      this.interceptors?.requestInterceptor,
      this.interceptors?.requestInterceptorCatcher
    )
    this.instance.interceptors.response.use(
      this.interceptors?.responseInterceptor,
      this.interceptors?.responseInterceptorCatcher
    )
    // 封装全局拦截器
    this.instance.interceptors.request.use(
      (config) => {
        if (this.showLoading) {
          this.loading = ElLoading.service({
            lock: true,
            text: '加载中...',
            fullscreen: true,
            background: '#f4f4f4'
          })
        }
        return config
      },
      (err) => {
        return err
      }
    )
    this.instance.interceptors.response.use(
      (res) => {
        // 将loading移除
        this.loading?.close()
        const data = res.data
        if (data.returnCode === '-1001') {
          console.log('请求失败')
        } else {
          return data
        }
      },
      (err) => {
        if (err.response.status === 404) {
          console.log('404错误')
          // 将loading移除
          this.loading?.close()
        }
        return err
      }
    )
  }
  request<T>(config: ZRequestConfig): Promise<T> {
    return new Promise((resolve, reject) => {
      // 单个请求对coder传入的config进行处理
      if (config.interceptors?.requestInterceptor) {
        config = config.interceptors.requestInterceptor(config) // 对请求进行拦截
      }
      // 判断请求接口是否显示loading 不传默认为true
      if (!config.showLoading) {
        this.showLoading = config.showLoading ? true : false
      }
      // request默认类型声明 request<T = any, R = AxiosResponse<T>, D = any>(config: AxiosRequestConfig<D>): Promise<R>
      this.instance
        .request<any, T>(config) // 上边全局拦截器钩子this.instance.interceptors.response.use已经对数据进行const data = res.data处理 但是此处ts推导出request返回值类型仍然是AxiosResponse 类型 正确应该是我们定义接口是的<T>类型
        .then((res) => {
          // 单个请求对数据的处理 判断是否有请求钩子
          if (config.interceptors?.responseInterceptor) {
            res = config.interceptors.responseInterceptor(res) // 对请求进行拦截
          }
          // 将showLoading设置为true 不影响下一个接口请求
          this.showLoading = true
          resolve(res)
        })
        .catch((err) => {
          console.log('requestError', err)
          reject(err)
          this.showLoading = true
        })
    })
  }
  get<T>(config: ZRequestConfig): Promise<T> {
    return this.request<T>({ ...config, method: 'GET' })
  }
  post<T>(config: ZRequestConfig): Promise<T> {
    return this.request<T>({ ...config, method: 'POST' })
  }
}

// src/service/index.ts
import ZRequest from './request/index'
import { BASE_URL, TIME_OUT } from './request/config'
export default new ZRequest({
  baseURL: BASE_URL,
  timeout: TIME_OUT,
  interceptors: {
    // 对单个baseUrl下的请求进行拦截
    requestInterceptor: (config) => {
      console.log('请求成功的拦截')
      return config
    },
    requestInterceptorCatcher: (err) => {
      console.log('请求失败的拦截')
      return err
    },
    responseInterceptor: (res) => {
      console.log('响应成功的拦截')
      return res
    },
    responseInterceptorCatcher: (err) => {
      console.log('响应失败的拦截')
      return err
    }
  }
})

使用

// src/main.ts
import zwhRequest from './service/index'
interface DataType {
  data: any
  returnCode: string
  success: boolean
}
zwhRequest
  .request<DataType>({
    url: '/home/multidata',
    method: 'GET',
    showLoading: true
  })
  .then((res) => {
    console.log(res)
  })

bak:学习来自coderwhy