Typescript封装axios

x33g5p2x  于2022-03-06 转载在 其他  
字(10.5k)|赞(0)|评价(0)|浏览(610)

一、认识axios
目前在开发中会使用axios来发送ajax请求,其具有以下几个特点:

1、在浏览器中发送 XMLHttpRequests 请求
2、在浏览器中发送 XMLHttpRequests 请求
3、 支持 Promise API
4、拦截请求和响应
5、转换请求和响应数据
等等...

支持多种请求方式:
axios(config)
axios.request(config)
axios.get(url[,config])
axios.delete(url[,config])
axios.head(url[,config ])
axios.post(url[,data[,config]])
axios.put(url[,data[,config]])
axios.patch(url[,data[,config]])
有时候我们需要同时发送两个请求,应该使用axios.all,可以放入多个请求的数组。
常见的一些配置选项

1、请求地址: 
url: '/url'
2、请求类型
method: 'get'
3、基本路径
baseURL: 'http://www.mt.com/api'
4、请求前的数据处理
 transformRequest:[function(data){}]
5、请求后的数据处理
transformResponse: [function(data){}],
6、自定义的请求头
headers:{'x-Requested-With':'XMLHttpRequest'},
7、 URL查询对象
params:{ id: 12 }
8、查询对象序列化函数
paramsSerializer: function(params){ }
9、request body
data: { key: 'aa'},
10、超时设置s
timeout: 1000
11、跨域是否带Token
withCredentials: false
12、自定义请求处理
adapter: function(resolve, reject, config){}
13、身份验证信息
auth: { uname: '', pwd: '12'},
14、响应的数据格式 json / blob /document /arraybuffer
responseType: 'json'

axios拦截器

//axios也可以设置拦截器,拦截每次请求和响应
axios.interceptors.request.use(请求成功拦截,请求失败拦截)
axios.interceptors.response.use(响应成功拦截,响应失败拦截)

二、基本使用
一、模拟get请求

二、get请求,并且传入参数

axios
  .get('http://httpbin.org/get', {
    params: {
      name: 'dmc',
      age: 18
    }
  })
  .then((res) => {
    console.log(res.data)
  })

三、post请求

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

四、promise中也是可以传入类型的

new Promise<string>((resolve, reject) => {
  resolve('hhhh')
}).then((res) => {
  console.log(res)
})
//这里可以将泛型传入其中

五、axios的配置选项

//一、全局配置
axios.defaults.baseURL = 'http://httpbin.org'
axios.defaults.timeout = 10000

//二、给每一个请求单独设置
axios.get('/get', {
	params:{
		name:'dmc',
		age: 20
	},
	timeout: 5000,
	headers:{}
})
  .then((res) => {
    console.log(res.data)
  })

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

六、axios.all 多个请求,以数组的形式一起返回

axios
  .all([
    axios.get('/get', { params: { name: 'why', age: 18 } }),
    axios.post('/post', { data: { name: 'why', age: 18 } })
  ])
  .then((res) => {
    console.log(res[0].data)
    console.log(res[1].data)
  })

七、axios的拦截器
在发起请求之前需要做的一些操作,或者在数据成功返回之前做的操作。

axios.interceptors.request.use((config) => {
	//想做的一些操作,给请求添加token,isLoading动画
	console.log('请求成功拦截')
	return config
}, (err) => {
	console.log('请求发送失败')
	return err
})

axios.interceptors.response.use((res) =>{
	console.log('响应成功的拦截')
	return res
}, (err) => {
	console.log('服务器相应失败')
	return err
})

三、封装
写在前面: 我们需要创建一个类,并且可以对其传入一些基本的配置信息来对其进行实例化,然后可以对不同的实例化对象进行发起请求。

上图所示,就是我们封装的思路。
拦截器封装:现在开始封装拦截器,首先我们需要封装三种拦截器,一个是全部的请求都存在的拦截器,也就是在Request类中的,第二个是我们给实例化的对象封装拦截器,该拦截器是可选的,也就是该实例化对象下面的所有请求都存在拦截器。第三个是我们给每一个请求封装拦截器,并且也是可选的。
MYRequest封装类

import axios from 'axios'
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
//这里是拦截器的接口类型
interface MYInterceptors<T = AxiosResponse> {
  requestInterceptors?: (config: AxiosRequestConfig) => AxiosRequestConfig
  requestInterceptorsCatch?: (error: any) => any
  responseInterceptors?: (res: T) => T
  responseInterceptorsCatch?: (error: any) => any
}
//请求对象config需要进行扩展
interface MYRequestConfig extends AxiosRequestConfig {
  interceptors?: MYInterceptors
}

class MYRequest {
  instance: AxiosInstance
  interceptors?: MYInterceptors
  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): void {
    this.instance.request(config).then((res) => {
      console.log(res)
    })
  }
}

export default MYRequest

实例化myRequest1

import MYRequest from './request'
import { BASE_URL, TIME_OUT } from './request/config'

const myRequest1 = new MYRequest({
  baseURL: BASE_URL,
  timeout: TIME_OUT,
  interceptors: {
    requestInterceptors: (config) => {
      console.log('触发myRequest1的请求成功拦截器')
      return config
    },
    requestInterceptorsCatch: (error) => {
      console.log('触发myRequest1的请求失败拦截器')
      return error
    },
    responseInterceptors: (res) => {
      console.log('触发myRequest1的响应成功拦截器')
      return res
    },
    responseInterceptorsCatch: (err) => {
      console.log('触发myRequest1的响应失败拦截器')
      return err
    }
  }
})

export default myRequest1

myRequest1的request请求

myRequest1.request({
  url: '/home/multidata'
})

配置所有请求的拦截器,此时这个拦截器就不再是可选的了。
MYRequest构造函数中添加如下代码

this.instance.interceptors.request.use(
      (config) => {
        console.log('MYRequest类的拦截器请求成功拦截器')
        return config
      },
      (err) => {
        console.log('MYRequest类的拦截器请求失败拦截器')
        return err
      }
    )

    this.instance.interceptors.request.use(
      (res) => {
        console.log('MYRequest类的拦截器响应成功拦截器')
        return res
      },
      (err) => {
        console.log('MYRequest类的拦截器响应失败拦截器')
        return err
      }
    )

给我们的每一个请求添加拦截器,此时我们应该将我们传入的配置的类型进行切换

request(config: MYRequestConfig): void {
    this.instance.interceptors.request.use(
      config.interceptors?.requestInterceptors,
      config.interceptors?.requestInterceptorsCatch
    )

    this.instance.interceptors.response.use(
      config.interceptors?.responseInterceptors,
      config.interceptors?.responseInterceptorsCatch
    )

    this.instance.request(config).then((res) => {
      console.log(res)
    })
  }
myRequest1.request({
  url: '/home/multidata',
  interceptors: {
    requestInterceptors: (config) => {
      console.log('myRequest1的request请求成功的拦截器')
      return config
    },
    requestInterceptorsCatch: (err) => {
      console.log('myRequest1的request请求失败的拦截器')
      return err
    },
    responseInterceptors: (config) => {
      console.log('myRequest1的request响应成功的拦截器')
      return config
    },
    responseInterceptorsCatch: (err) => {
      console.log('myRequest1的request响应失败的拦截器')
      return err
    }
  }
})

上面拦截器我们已经设置好了,接下来我们将设置返回值。
下面我们通过return Promsie来拿到返回值,并且通过泛型将参数类型传入其中。

request<T>(config: MYRequestConfig): Promise<T> {
    return new Promise((resolve, reject) => {
      this.instance.interceptors.request.use(
        config.interceptors?.requestInterceptors,
        config.interceptors?.requestInterceptorsCatch
      )

      this.instance.interceptors.response.use(
        config.interceptors?.responseInterceptors,
        config.interceptors?.responseInterceptorsCatch
      )

      this.instance
        .request(config)
        .then((res) => {
          resolve(res.data)
        })
        .catch((err) => {
          reject(err)
        })
    })
  }
myRequest1
  .request<DataType>({
    url: '/home/multidata',
    interceptors: {
      requestInterceptors: (config) => {
        console.log('myRequest1的request请求成功的拦截器')
        return config
      },
      requestInterceptorsCatch: (err) => {
        console.log('myRequest1的request请求失败的拦截器')
        return err
      },
      responseInterceptors: (config) => {
        console.log('myRequest1的request响应成功的拦截器')
        return config
      },
      responseInterceptorsCatch: (err) => {
        console.log('myRequest1的request响应失败的拦截器')
        return err
      }
    }
  })
  .then((res) => {
    console.log(res.data)
    console.log(res.returnCode)
    console.log(res.success)
  })

接下来配置其他的请求

get<T>(config: MYRequestConfig): Promise<T> {
    return this.request<T>({ ...config, method: 'GET' })
  }

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

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

  patch<T>(config: MYRequestConfig): Promise<T> {
    return this.request<T>({ ...config, method: 'PATCH' })
  }

最终实现代码:
MYRequest函数封装

import axios from 'axios'
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import { LoadingInstance } from 'element-plus/lib/components/loading/src/loading'
import { ElLoading } from 'element-plus'

const DEFAULT_SHOW = true

interface MYInterceptors<T = AxiosResponse> {
  requestInterceptors?: (config: AxiosRequestConfig) => AxiosRequestConfig
  requestInterceptorsCatch?: (error: any) => any
  responseInterceptors?: (res: T) => T
  responseInterceptorsCatch?: (error: any) => any
}

interface MYRequestConfig extends AxiosRequestConfig {
  interceptors?: MYInterceptors
  isShowLoading?: boolean
}

class MYRequest {
  instance: AxiosInstance
  interceptors?: MYInterceptors
  loading?: LoadingInstance
  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
    )

    this.instance.interceptors.request.use(
      (config) => {
        console.log('MYRequest类的拦截器请求成功拦截器')
        this.loading = ElLoading.service({
          lock: true,
          text: '正在请求数据....',
          background: 'rgba(0, 0, 0, 0.5)'
        })
        return config
      },
      (err) => {
        console.log('MYRequest类的拦截器请求失败拦截器')
        return err
      }
    )

    this.instance.interceptors.response.use(
      (res) => {
        console.log('MYRequest类的拦截器响应成功拦截器')
        this.loading?.close()
        return res
      },
      (err) => {
        console.log('MYRequest类的拦截器响应失败拦截器')
        this.loading?.close()
        return err
      }
    )
  }

  request<T>(config: MYRequestConfig): Promise<T> {
    return new Promise((resolve, reject) => {
      this.instance.interceptors.request.use(
        config.interceptors?.requestInterceptors,
        config.interceptors?.requestInterceptorsCatch
      )

      this.instance.interceptors.response.use(
        config.interceptors?.responseInterceptors,
        config.interceptors?.responseInterceptorsCatch
      )
      if (config.isShowLoading === false) {
        // this.isShowLoading = false
      }

      this.instance
        .request(config)
        .then((res) => {
          resolve(res.data)
        })
        .catch((err) => {
          reject(err)
        })
    })
  }

  get<T>(config: MYRequestConfig): Promise<T> {
    return this.request<T>({ ...config, method: 'GET' })
  }

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

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

  patch<T>(config: MYRequestConfig): Promise<T> {
    return this.request<T>({ ...config, method: 'PATCH' })
  }
}

export default MYRequest

myRequest1实例化代码

import MYRequest from './request'
import { BASE_URL, TIME_OUT } from './request/config'

const myRequest1 = new MYRequest({
  baseURL: BASE_URL,
  timeout: TIME_OUT,
  interceptors: {
    requestInterceptors: (config) => {
      console.log('触发myRequest1的请求成功拦截器')
      return config
    },
    requestInterceptorsCatch: (error) => {
      console.log('触发myRequest1的请求失败拦截器')
      return error
    },
    responseInterceptors: (res) => {
      console.log('触发myRequest1的响应成功拦截器')
      return res
    },
    responseInterceptorsCatch: (err) => {
      console.log('触发myRequest1的响应失败拦截器')
      return err
    }
  }
})

export default myRequest1

myRequest1.request代码

import { createApp } from 'vue'
import App from './App.vue'

import router from './router/index'
import store from './store'
import register from './global'

import myRequest1 from './service'

interface DataType {
  data: any
  returnCode: string
  success: boolean
}

myRequest1
  .request<DataType>({
    url: '/home/multidata',
    interceptors: {
      requestInterceptors: (config) => {
        console.log('myRequest1的request请求成功的拦截器')
        return config
      },
      requestInterceptorsCatch: (err) => {
        console.log('myRequest1的request请求失败的拦截器')
        return err
      },
      responseInterceptors: (config) => {
        console.log('myRequest1的request响应成功的拦截器')
        return config
      },
      responseInterceptorsCatch: (err) => {
        console.log('myRequest1的request响应失败的拦截器')
        return err
      }
    }
  })
  .then((res) => {
    console.log(res.data)
    console.log(res.returnCode)
    console.log(res.success)
  })

const app = createApp(App)
app.use(router)

register(app)
app.use(store)
app.mount('#app')

相关文章