封装 axios.ts

201 阅读2分钟

axios 的基本使用

import axios from 'axios'

// axios 配置(全局)
axios.defaults.baseURL = 'http://httpbin.org'
axios.defaults.timeout = 6000
axios.defaults.headers = {}

// 请求拦截器
axios.interceptors.request.use(
  // 请求发送成功
  (config) => {
    // 进行一些操作
    
    return config
  },
  // 请求发送失败
  (err) => {
    console.log(err)
  }
)

// 响应拦截器
axios.interceptors.response.use(
  // 服务器响应成功
  (res) => {
    // 进行一些操作
    
    return res.data
  },
  // 服务器响应失败
  (err) => {
    console.log(err)
  }
)

// 发送 axios 请求
axios
  .get('/get', {
    params: { name: 'kobe', age: 18 },
    timeout: 3000,  // 单个请求配置
    headers: {}
  })
  .then((res) => {
    console.log(res.data, 'get')
  })

axios
  .post('/post', {
    data: { name: 'kobe', age: 18 }
  })
  .then((res) => {
    console.log(res.data)
  })

封装思路

为了实现更好的封装性,我们使用类来封装。而且考虑到拓展性,我们不是直接使用默认的 axios 实例,而是使用 axios.create 来创建多个实例。

在之前的封装思路中,我们实际上是没有考虑到多个实例的情况,默认是只存在一个 axios 实例。但是实际开发中可能会出现多个实例。所以我们封装如下代码

import axios from 'axios'
import type { AxiosInstance, AxiosRequestConfig } from 'axios'

// 定义类
class MyRequest {
  instance: AxiosInstance

  constructor(config: AxiosRequestConfig) {
    this.instance = axios.create(config)

    // 在创建 axios 实例的时候调用拦截器
    // 这些拦截器是在所有实例中都会进行拦截的
    this.instance.interceptors.request.use(
      (config) => {
        console.log('请求发送成功')
        return config
      },
      (error) => {
        console.log('请求发送失败')
      }
    )
    this.instance.interceptors.response.use(
      (res) => {
        console.log('服务器响应成功')
        return res
      },
      (error) => {
        console.log('服务器响应失败')
      }
    )
  }
  
  request(config: AxiosRequestConfig) {
    this.instance.request(config).then((res) => {
      console.log(res.data)
    })
  }
}

export default MyRequest
import MyRequest from './request'

import { BASR_URL, TIME_OUT } from './request/config'

// 创建一个 axios 实例,配置相关属性
// 不同的实例可以配置不同的基准属性
const requestInstance = new MyRequest({
  baseURL: BASR_URL,
  timeout: TIME_OUT
})

requestInstance.request({
  method: 'GET'
})

考虑到代码的拓展性,我们可以给不同的 axios 实例添加不同的拦截器。

在创建 axios 实例时传入 interceptors 属性,用来自定义拦截器。

这个拦截器只有在当前实例请求时才会进行拦截。

const requestInstance = new MyRequest({
  baseURL: BASR_URL,
  timeout: TIME_OUT,
  interceptors: {
    requestInterceptors: (config) => {
      return config
    }
  }
})

但是由于创建 axios 实例的参数类型是定好的,所以我们要自定义一些接口。

import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios'

// 自定义拦截器的接口
interface MyRequestInterceptors {
  requestInterceptors?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig
  requestInterceptorsCatch?: (error: any) => any
  responseInterceptors?: (res: AxiosResponse) => AxiosResponse
  responseInterceptorsCatch?: (error: any) => any
}

interface MyRequestConfig extends AxiosRequestConfig {
  interceptors?: MyRequestInterceptors
}
class MyRequest {
  instance: AxiosInstance
  interceptors?: MyRequestInterceptors

  constructor(config: MyRequestConfig) {
    this.instance = axios.create(config)
    this.interceptors = config.interceptors

    this.instance.interceptors.request.use(
      this.interceptors?.requestInterceptors,
      this.interceptors?.requestInterceptorsCatch
    )
    this.instance.interceptors.response.use(
      this.interceptors?.responseInterceptors,
      this.interceptors?.responseInterceptorsCatch
    )
  }

  request(config: AxiosRequestConfig) {
    this.instance.request(config).then((res) => {
      console.log(res)
    })
  }
}

这样我们就可以通过在创建 axios 实例时传入不同的拦截器实现它的拓展了。