前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Axios的封装思想及实践(TS版本)

Axios的封装思想及实践(TS版本)

作者头像
玖柒的小窝
修改于 2021-10-26 07:32:38
修改于 2021-10-26 07:32:38
2.6K00
代码可运行
举报
文章被收录于专栏:各类技术文章~各类技术文章~
运行总次数:0
代码可运行

源于coderWhy教学视频思想,对axios做一个简单的小结,再次感谢coderwhy大神

Axios官网(中文):Axios (axios-http.com)

基本安装

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//npm方式
npm install axios
//yarn方式
yarn add axios
复制代码

基本使用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
axios(config)
axios.request(config)
axios.get(config)
axios.post(config)
复制代码

缺点是耦合度太高,相同配置需多次重复,且不灵活

封装思想

  • 直接使用axios,依赖性太强,如果今后更换网络请求库会很麻烦
  • 一些公共的请求功能,每次请求都需要重写配置
  • aixos进行加一层封装,将axios封装为自定义的request,将来直接使用request来发送网络请求就行,日后想要更换网络请求库,可以直接修改request层,将一些公共的功能封装在request层,如网络请求头添加Authorization(即token),加载loading效果等等,拦截器可以灵活封装

使用Typescript进行封装的一些前置知识梳理

  1. axios(config)config的类型为AxiosRequestConfig,具体见官网:请求配置 | Axios 中文文档 (axios-http.cn) 常用的有几个:url,method,baseUrl,data,timeout等 默认配置可以进行升级改造,新建一个接口实现AxiosRequestConfig,在其中添加一些新的配置
  2. AxiosResponse---axios默认的返回值类型,接收泛型T默认为any,代表的是实际接收到的返回数据类型,一般会将T设置为IDataType。 //一般情况下我们只使用data export interface AxiosResponse<T = any> { data: T; status: number; statusText: string; headers: any; config: AxiosRequestConfig; request?: any; } //一般在使用中,我们会将返回数据类型定义为如下形式 export interface IDataType<T = any> { status: string msg: string data: T } 复制代码 日常使用中,我们不会使用AxiosResponse作为封装后的返回值数据类型,会提取其中的data,可以通过在响应成功拦截器中返回result.data来实现(后面会详细介绍),而data的类型即为IDataType
  3. 封装统一使用原生实例的request方法来进行 //T默认是any类型,返回值默认是AxiosResponse<T> request<T = any, R = AxiosResponse<T>> (config: AxiosRequestConfig): Promise<R>; 复制代码 封装后实现的效果如下: //T即为IDataType类型,返回的是一个Promise<T> xxRequest.get<T>(config: xxRequestConfig<T>): Promise<T> 复制代码

一、封装一(去耦合)

  1. 创建自定义网络请求类JJRequest,将axios实例包装在内 //service/request/request.ts class JJRequest { instance: AxiosInstance constructor(config: AxiosRequestConfig) { this.instance = axios.create(config) } //返回的Promise中结果类型为AxiosResponse<any> request(config: AxiosRequestConfig): Promise<AxiosResponse> { return new Promise<AxiosResponse>((resolve, reject) => { this.instance .request(config) .then((res) => { resolve(res) }) .catch((err) => { reject(err) }) }) } } 复制代码
  2. 创建实例(仅配置基本的baseURLtimeout,属于实例级别配置) //service/index.ts //使用环境配置 const jjRequest = new JJRequest({ baseURL: process.env.VUE_APP_BASE_URL, timeout: process.env.VUE_APP_TIME_OUT }) 复制代码
  3. 具体使用 //main.ts jjRequest .request({ url: '/xxx' }) .then((res) => { console.log(res) }) 复制代码

查看结果:可以看出结果为AxiosResponse<any>类型

二、封装二(添加全局级别拦截)

原生的拦截器位于axiosInstance实例中,使用方法是(来源官网:拦截器 | Axios 中文文档 (axios-http.cn)

注意:响应成功和响应失败的判别标准,以状态码2xx为界限,超出的响应失败

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    return config;
  }, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  });

// 添加响应拦截器
axios.interceptors.response.use(function (response) {
    // 2xx 范围内的状态码都会触发该函数。
    // 对响应数据做点什么
    return response;
  }, function (error) {
    // 超出 2xx 范围的状态码都会触发该函数。
    // 对响应错误做点什么
    return Promise.reject(error);
  });
复制代码

全局拦截在JJRequest的构造函数中实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//service/request/request.ts
//省略前后部分代码
//....
constructor(config: AxiosRequestConfig) {
  this.instance = axios.create(config)
  
  //全局请求拦截
  this.instance.interceptors.request.use(
      (config) => {
        console.log(config)
        return config
      },
      (error) => {
        console.log('全局请求失败拦截', error)
      }
    )
  //全局响应拦截
    this.instance.interceptors.response.use(
      (res) => {
        //res为AxiosResponse类型,含有config\data\headers\request\status\statusText属性
        console.log(res)
        //改造返回的数据类型,即将AxiosResponse的data返回
        return res.data
      },
      (error) => {
        console.log('全局响应失败拦截')
        console.log(error.request)//
        console.log(error.response)
        return error
      }
    )
  
  //加入泛型限定,返回数据类型为T,
  request<T>(config: AxiosRequestConfig<T>): Promise<T> {
    return new Promise<T>((resolve, reject) => {
      this.instance
        .request<any, T>(config)
        .then((res) => {
          resolve(res)
        })
        .catch((err) => {
          reject(err)
        })
    })
  }
}
复制代码

实际使用时如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//main.ts==>返回的数据类型限定为IDataType
jjRequest
  .request<IDataType>({
    url: '/xxx'
  })
  .then((res) => {
    console.log(res)
  })
  .catch((err) => {
    console.log('=====', err)
  })
复制代码

同封装一的接口在main.ts中运行后效果如下,只剩下AxiosResponse中的data,此处为自定义的IDataType类型,暂时还未明确加入泛型,后面会加入

演示响应失败的拦截:(将后端接口中的/xxx改为了/xxxx,则前端访问/xxx将出现响应失败404

三、封装三(自定义实例级别的拦截器,添加token)

需实现的效果如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//service/index.ts
const jjRequest = new JJRequest({
  baseURL: process.env.VUE_APP_BASE_URL,
  timeout: process.env.VUE_APP_TIME_OUT,
  //实例级别的拦截器,在创建axios实例的时候携带拦截器
  interceptors:{
    requestInterceptor: ...
    requestInterceptorCatch: ...
    responseInterceptor: ...
    responseInterceptorCatch: ...
  }
})
复制代码

因为原生的AxiosRequestConfig中没有拦截器配置这个属性,因此需要自定义改造,一是自定义拦截器接口,二是自定义请求配置接口

  1. 自定义拦截器接口(共四个拦截器,四个函数) interface IJJRequestInterceptors<T = AxiosResponse> { //请求成功 requestInterceptor?: (config: AxiosRequestConfig) => AxiosRequestConfig //请求失败 requestInterceptorCatch?: (error: any) => any //响应成功 responseInterceptor?: (res: T) => T //响应失败 responseInterceptorCatch?: (error: any) => any } 复制代码
  2. 自定义请求配置接口,可选属性,可配可不配 interface IJJRequestConfig<T = AxiosResponse> extends AxiosRequestConfig { interceptors?: IJJRequestInterceptors<T> } 复制代码
  3. 改造网络请求类 class JJRequest { instance: AxiosInstance //该属性从实例中获取 interceptors?: IJJRequestInterceptor constructor(config: IJJRequestConfig) { this.instance = axios.create(config) //从实例配置config中获取拦截器配置 this.interceptors = config.interceptors //全局请求拦截 this.instance.interceptors.request.use(..., ...) //全局响应拦截 this.instance.interceptors.response.use(..., ...) //实例级别拦截 this.instance.interceptors.request.use( this.interceptors?.requestInterceptor, this.interceptors?.requestInterceptorCatch ) this.instance.interceptors.response.use( this.interceptors?.responseInterceptor, this.interceptors?.responseInterceptorCatch ) } } 复制代码
  4. 创建实例 const jjRequest = new JJRequest({ baseURL: process.env.VUE_APP_BASE_URL, timeout: process.env.VUE_APP_TIME_OUT, interceptors: { requestInterceptor: (config) => { //此处token在开发中可从localStorage中获取,token一般从服务器获取存在vuex中,然后转存到localStorage中,自己封装关于localStorage的方法,此处用一个常量代替 //const token = localCache.getCache('token') const token = 'this ia a token' if (token) { config.headers.Authorization = `Bearer ${token}` } return config } } }) 复制代码

结果展示

四、封装四(单个请求调用级别的拦截)

实现调用级别的拦截,需要在request方法中做文章,将其参数类型也由AxiosRequestConfig升级为IJJRequestConfig,实现的思路是直接调用该方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//service/request/request.ts
//...
request<T>(config: IJJRequestConfig<T>): Promise<T> {
    return new Promise<T>((resolve, reject) => {
      //请求拦截设置位置
      if (config.interceptors?.requestInterceptor) {
        config = config.interceptors.requestInterceptor(config)
      }

      this.instance
        .request<any, T>(config)
        .then((res) => {
          //响应拦截设置位置
          if (config.interceptors?.responseInterceptor) {
            res = config.interceptors.responseInterceptor(res)
          }
          resolve(res)
        })
        .catch((err) => {
          console.log('=====', err)
          reject(err)
        })
    })
  }
复制代码

调用时如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
jjRequest
  .request<IDataType>({
    url: '/xxx',
  //单个请求调用级别单独设置拦截器
    interceptors: {
      //直接返回IDataType类型结果中的data属性项
      responseInterceptor: (res) => res.data
    }
  })
  .then((res) => {
    console.log(res)
  })
  .catch((err) => {
    console.log('=====', err)
  })
复制代码

结果如下

五、封装五(封装get、post等,方便调用)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 //service/request/request.ts
 //....
 get<T = any>(config: IJJRequestConfig<T>): Promise<T> {
     return this.request<T>({
       ...config,
       method: 'GET'
     })
   }
 ​
   post<T = any>(config: IJJDRequestConfig<T>): Promise<T> {
     return this.request<T>({
       ...config,
       method: 'POST'
     })
   }
   //其余patch、delete等参照一样的,实际调用时可直接使用jjRequest.get<IDataType>(config)来请求数据
复制代码

axios的封装划分了三层

  • 全局层
  • 实例层
  • 单个请求层

将来可以根据实际情况做相应的封装,主要考虑的是将封装放在哪一层来做,本文主要是写一写封装的思想 例如loading加载效果,可以在全局来做,也可以在实例层来做,也可以在单个请求处来做,看具体需求!此处就不在做具体的封装,仅做抛砖引玉的作用!

补充:拦截的执行顺序

对于axios的封装还有很多,比如关于重复请求的封装、参数序列化等,按需进行即可。ps:主要是我还不会,哈哈。。

来自一个业余程序爱好者小弟的小结,不足之处,请各位大佬指正!

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基本安装
  • 基本使用
  • 封装思想
  • 一、封装一(去耦合)
  • 二、封装二(添加全局级别拦截)
  • 三、封装三(自定义实例级别的拦截器,添加token)
  • 四、封装四(单个请求调用级别的拦截)
  • 五、封装五(封装get、post等,方便调用)
  • 补充:拦截的执行顺序
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档