4-封装axios

源码github连接:baojinghui/MyAxios (github.com)

1,为什么要封装axios ,因为当一个库不维护时,便于在封装的地方把不维护的库替换掉

2,因为axios返回的是一个实例对象,所以只能这一个实例上修改。但是我们的接口有两种baseUrl,就可以通过封装,不同的接口创建新的实例去配置,不同实例互不干扰。

3,配置拦截器,给不同的实例配置不同的拦截器,支持以对象形式接受多个拦截器配置

4,一般情况下一个实例就够用了,在大行项目中可以使用到多个实例

目录结构:

类型声明:

/*-------------------------  TS封装拦截器的接口  -------------------------------------*/

//导入axios的  实例的类型      请求参数的类型      响应数据的类型
import type { AxiosRequestConfig } from 'axios'

//扩展拦截器的类型,支持传入一个对象,对象中可同时传入多个回调,可以同时包含响应器和拦截器的配置
export interface MyInterceptors {
  //请求拦截器和请求拦截器捕获错误的类型
  resquestInterceptors?: (config: AxiosRequestConfig) => AxiosRequestConfig
  resquestInterceptorsCatch?: (err: any) => any
  //响应拦截器和响应拦截器捕获错误的类型
  responseInterceptors?: (config: any) => any //AxiosResponse
  responseInterceptorsCatch?: (err: any) => any
}
//类型扩展,把axios上的类型,扩展到自己定义的接口上,使请求参数支持传入一个对象
export interface MyRequestConfig extends AxiosRequestConfig {
  interceptors?: MyInterceptors //扩展后的拦截器
  showLoading?: boolean //是否显示加载动画
}

 基于axios封装的类:

//封装一个axios的类,每次使用时生成一个新的实例,这样配置多种不同服务器请求的接口
import axios from 'axios'
//导入axios的  实例的类型
import type { AxiosInstance } from 'axios'
//导入扩展后的接口类型 和扩展后的请求参数类型
import type { MyInterceptors, MyRequestConfig } from './types'
//导入请求动画组件
import { ElLoading } from 'element-plus'
// 导入请求动画实例的类型,用于取消动画
import { LoadingInstance } from 'element-plus/lib/components/loading/src/loading'
//封装axios
class MyAxios {
  instance: AxiosInstance //实例
  interceptors?: MyInterceptors //拦截器
  loading?: LoadingInstance //加载动画
  showLoading?: boolean //是否显示请求的动画
  //config的类型改为加了自己扩展后的类型:AxiosRequestConfig--->MyRequestConfig,
  //上面会增加interceptors接口,支持同时传入多个拦截器,和接受是否显示动画的配置
  constructor(config: MyRequestConfig) {
    //每次调用instance都会产生一个新的实例,在新的实例上面配置新的baseurl等配置
    this.instance = axios.create(config)
    //保存一份传入的所有拦截器
    this.interceptors = config.interceptors
    //默认显示请求动画:showLoading默认为true
    this.showLoading = config.showLoading ?? true
    //使用实例身上的请求拦截器和响应拦截器的方法,把传入拦截器对象中的方法依次传入
    this.instance.interceptors.request.use(
      this.interceptors?.resquestInterceptors,
      this.interceptors?.resquestInterceptorsCatch
    )
    this.instance.interceptors.response.use(
      this.interceptors?.responseInterceptors,
      this.interceptors?.responseInterceptorsCatch
    )
    //但是有些拦截器配置每个实例都会需要,
    //如请求时的动画,需要全局配置,让每个实例中都存在,就直接使用axios上面的拦截器进行封装
    this.instance.interceptors.request.use(
      (config) => {
        console.log('全局拦截成功')
        //全局配置loading动画,拿下loading
        if (this.showLoading)
          this.loading = ElLoading.service({
            lock: true,
            text: '正在加载...',
            background: 'rgba(0,0,0,0.5)',
          })
        return config
      },
      (err) => {
        console.log('全局拦截失败')
        return err
      }
    )
    this.instance.interceptors.response.use(
      (res) => {
        setTimeout(() => {
          this.loading?.close()
        }, 1000)
        console.log('全局响应成功')
        const data = res.data
        if (data.returnCode == '-1001') {
          console.log('请求失败')
        } else {
          return data
        }
      },
      (err) => {
        console.log('全局响应失败')
        this.loading?.close() //移除加载动画
        if (err.response.status === 404) {
          console.log('404错误信息')
        }
        return err
      }
    )
  }

  //封装request请求
  //请求参数config要用自己扩展后的接口(MyRequestConfig),才支持传入对象形式的拦截器
  request<T>(config: MyRequestConfig): Promise<T> {
    return new Promise((resolve, resject) => {
      //还可以给单个请求配置拦截器
      if (config.interceptors?.resquestInterceptors) {
        //如果存在说明配置了单个请求的拦截器,就把转换后的config返回给config继续处理
        //config.interceptors.resquestInterceptors(config)返回的是一个处理过后的config
        config = config.interceptors.resquestInterceptors(config)
      }
      //请求动画默认false,如果showloading为false,就是关闭请求动画
      if (config.showLoading === false) {
        this.showLoading = config.showLoading
      }
      //使用axios自身的request发请求
      this.instance
        .request<any, T>(config)
        .then((res) => {
          //如果为真说明配置了单个请求的响应拦截器,就把转换后的res返回给res继续处理
          //config.interceptors.resquestInterceptors(res)返回的是一个处理过后的res
          if (config.interceptors?.responseInterceptors) {
            res = config.interceptors.responseInterceptors(res)
          }
          //让动画显示,即使上面不显示动画的请求完也设置,这样不影响后面的动画显示
          this.showLoading = true
          resolve(res)
        })
        .catch((err) => {
          this.showLoading = true
          resject(err)
        })
    })
  }
  //封装get请求,就是再get内部调request
  get<T>(config: MyRequestConfig): Promise<T> {
    return this.request<T>({ ...config, method: 'GET' })
  }
  //封装post请求,就是再post内部调request
  post<T>(config: MyRequestConfig): Promise<T> {
    return this.request<T>({ ...config, method: 'GET' })
  }
  //封装delete请求,就是再delete内部调request
  delete<T>(config: MyRequestConfig): Promise<T> {
    return this.request<T>({ ...config, method: 'GET' })
  }
  //封装patch请求,就是再patch内部调request
  patch<T>(config: MyRequestConfig): Promise<T> {
    return this.request<T>({ ...config, method: 'GET' })
  }
}
export default MyAxios

创建实例:

//配置MyAxios的实例并导出
import MyAxios from './request/index' //导入axios
import { BASE_URL, TIME_OUT } from '@/service/request/config' //导入环境变量
const myAxios = new MyAxios({
  baseURL: BASE_URL,
  timeout: TIME_OUT,
  //可选,单个实例的拦截器
  interceptors: {
    resquestInterceptors(config) {
      console.log('实例请求拦截成功')
      return config
    },
    resquestInterceptorsCatch(err) {
      console.log('实例请求拦截失败')
      return err
    },
    responseInterceptors(res) {
      console.log('实例响应拦截成功')
      return res
    },
    responseInterceptorsCatch(err) {
      console.log('实例请求拦截失败')
      return err
    },
  },
})
//导出封装的实例
export default myAxios

发送请求演示:

得到的返回值是我们传入接口的类型

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值