前端学习笔记(16)-Axios封装

1.Axios介绍

1.1 概述
Vue前端开发少不了向服务器请求数据,我们选择axios插件,他是一款功能强大,且易用的网络请求工具。
1.2 全称

ajax i/o system

1.3 功能介绍
1.3.1 axios功能特点
  • 在浏览器中发送 XMLHttpRequests 请求

  • 在 node.js 中发送 http请求

  • 支持 Promise API

  • 拦截请求和响应

  • 转换请求和响应数据

1.3.2 支持多种请求方式
  • axios(config)

  • axios.request(config)

  • axios.get(url[, config])

  • axios.delete(url[, config])

  • axios.head(url[, config])

    扫描二维码关注公众号,回复: 14790666 查看本文章
  • axios.post(url[, data[, config]])

  • axios.put(url[, data[, config]])

  • axios.patch(url[, data[, config]])

2.axios网络请求最基本流程

2.1导入(安装就省略了)
import axios from 'axios'
2.2 简单的实例
axios({     
  // 配置代码   
  url:'xxx',    // 设置请求的地址
  method:"GET", // 设置请求方法
  params:{      // get请求使用params进行参数凭借,如果是post请求用data
    type: '',
    page: 1
  }
}).then(res => {  
  // res为后端返回的数据
  console.log(res);   
})

method中是axios的请求类型方法, 而url为请求的URL地址,在then方法中获取服务器返回的数据并处理。

2.2.5 axios全局可配置项列表

这些是创建请求时可以用的配置选项。只有 url 是必需的。

配置项及示例

说明

url: '/user',

请求地址

method: 'get',

响应头信息

baseURL: ‘http://www.xxx.com/api’,

请根路径

transformRequest:[function(data){}],

请求前的数据处理

transformResponse: [function(data){}],

请求后的数据处理

headers:{'x-Requested-With':'XMLHttpRequest'},

自定义的请求头

params:{ id: 12 },

URL查询对象

paramsSerializer: function(params){ }

查询对象序列化函数

data: { key: 'aa'},

request body

timeout: 1000,

超时设置(s)

withCredentials: false

跨域是否带Token

adapter: function(resolve, reject, config){},

自定义请求处理

auth: { uname: '', pwd: '12'},

身份验证信息

responseType: 'json',

响应的数据格式 json / blob /document /arraybuffer / text / stream

2.3 对响应结果进行处理
.then((data) => {
  // todo: 真正业务逻辑代码
  console.log(data);
}, (err) => {
  // 错误处理代码  
  if (err.response.status === 401) {
  // handle authorization error
  }
  if (err.response.status === 403) {
  // handle server forbidden error
  }
  // 其他错误处理.....
  console.log(err);
});

在.then中可以写一些业务逻辑代码,或是对传回来响应结果的错误信息进行处理。

2.3.5 axios响应结果列表

响应结果

说明

data

实际响应回来的数据

header

响应头信息

status

响应状态码

statusText

响应状态信息

以上就是一个比较简单的axios请求流程,但是当随着项目规模增大,如果每发起一次HTTP请求,就要把这些比如设置超时时间、设置请求头、根据项目环境判断使用哪个请求地址、错误处理等等操作,都需要写一遍,这种重复劳动浪费时间,还会造成代码的冗余以及难以维护的问题,为了提高我们的代码质量,我们应该在项目中二次封装axios 再使用。

3.axios封装

3.1 axios拦截器

在正常项目中,我们需要对发起的请求进行拦截,或是在响应被 then 或 catch 处理前拦截以实现一些业务功能。比如一些网站过了一定的时间不进行操作,就会退出登录让你重新登陆页面,或是取消重复请求,axios自带的拦截器可以很好的完成这些功能。

其一般分为两种:请求拦截器、响应拦截器。

请求拦截器:在请求发送前进行必要操作处理,例如添加统一cookie、请求体加验证、设置请求头、处理请求token的统一注入问题等,相当于是对每个接口里相同操作的一个封装;

在请求拦截器中拦截了请求后,我们需要将请求继续转发出去,让请求访问服务器。这样请求才能成功,返回服务器数据。

config是拦截器拦截到所请求的配置信息,继承了AxiosRequestConfig接口,无论什么时候都需要return config,否则报错。

const instance = axios.create({})
// 请求拦截
    instance.interceptors.request.use(
      (config) => {
          // 在发送请求之前做些什么
           return config;
      },
      (error: any) => { 
          // 对请求错误做些什么
        return Promise.reject(error)
      }
    )

响应拦截器:同理,响应拦截器也是如此功能,只是在请求得到响应之后,对响应体的一些处理,通常是数据统一处理等,也常来判断登录失效等。

instance.interceptors.response.use(
      (res: any) => {
        // 2xx 范围内的状态码都会触发该函数。
        // 对响应数据做点什么
        let msg = res.data['msg'] || '未知错误,请联系管理员'
        switch (code) {
          case 401:
            msg = '认证失败,无法访问系统资源'
            break
            //......
          case 'default':
            msg = '系统未知错误'
            break
        }
        if (code === 200) {
          return Promise.resolve(res)
        } else {
          //ElMessage.error(msg)
          return Promise.reject(res)
        }
      },
      (error: any) => {
        // 超出 2xx 范围的状态码都会触发该函数
        // 对响应错误做点什么
        return Promise.reject(error)
      }
    )
3.2 如何封装

对于冗余重复的代码,很容易想到创建一个网络请求类的.ts文件,和后端协商好一些约定,请求头,状态码,请求超时时间等;并创建axios实例,设置请求头与超时时间。编写请求方法,也就是根据常用的get、post进行一个再次封装,使用时直接调用。对于项目所需要的添加统一cookie、请求体加验证、设置请求头的功能,以及错误处理,利用3.1所介绍的拦截器实现。

3.2.1 设置请求头与超时时间、接口请求前缀

根据开发、测试、生产环境的不同,接口请求前缀需要加以区分,在全局设置更为合适。大部分情况下,请求头等大部分配置也都是固定的,先将请求头作为基础配置。当需要一些特殊的请求头时,将特殊请求头作为参数传入,覆盖基础配置。

const instance = axios.create({
      baseURL: process.env.VUE_APP_INTERFACE,
      timeout: 5000,
      headers: {
        'Content-Type': 'application/json;charset=UTF-8',
      },
    })
3.2.2 封装拦截器

查看axios源代码会发现axios继承了AxiosInstance接口,而AxiosInstance返回的类型就是Promise,编写一个interceptors方法,将创建好的axios实例,配置传入,完成拦截器配置。

interceptors(instance: AxiosInstance) {
    // 请求拦截
    instance.interceptors.request.use(
      config => {
          // 在发送请求之前做些什么
        return config;
      },
      (error: any) => { 
          // 对请求错误做些什么
        return Promise.reject(error)
      }
    )
    // 响应拦截
    instance.interceptors.response.use(
      (res: any) => {
        // 2xx 范围内的状态码都会触发该函数。
        // 对响应数据做点什么
        let msg = res.data['msg'] || '未知错误,请联系管理员'
        switch (code) {
          case 401:
            msg = '认证失败,无法访问系统资源'
            break
            //......
          case 'default':
            msg = '系统未知错误'
            break
        }
        if (code === 200) {
          return Promise.resolve(res)
        } else {
          //ElMessage.error(msg)
          return Promise.reject(res)
        }
      },
      (error: any) => {
        // 超出 2xx 范围的状态码都会触发该函数
        // 对响应错误做点什么
        return Promise.reject(error)
      }
    )
  }
3.2.3 封装请求方法

axios继承了AxiosInstance接口,而AxiosInstance返回的类型就是Promise,我们不需要手动创建Promise对象,而是使用axios本身返回的Promise对象

export default function request(options: AxiosRequestConfig) {
    // 配置拦截器
    interceptors(instance)
    return instance(options)
  }

调用请求方法获取Promise对象

    request({
        url: "/sys/...",
        method: "post",
      }).then((res) => {
        console.log(res);
      });
    });

以上仅提供一种方式,封装 axios 没有一个绝对的标准,只要你的封装可以满足你的项目需求,并且用起来方便,那就是一个好的封装方案。

4.遇到的问题

4.1config.headers的对象可能未定义
4.1.1 原因

这是axios 0.26.1版本的AxiosRequestConfig里面的headers的类型定义:

(property) AxiosRequestConfig<D = any>.headers?: AxiosRequestHeaders | undefined

而早版本版本的AxiosRequestConfig里面的headers的类型定义:

(property) AxiosRequestConfig.headers?: any

先前版本的headers是any类型的,但config.headers确实有可能是undefined类型。用之前版本的axios就不会报错,但如何在这个版本解决报错呢?

4.1.2 解决

用接口类型进行typeScript的类型覆盖:

interface AxiosType extends AxiosRequestConfig {
  headers?: any
}
interceptors(instance: AxiosInstance) {
    // 请求拦截
    instance.interceptors.request.use(
      (config: AxiosType )=> {
          // 在发送请求之前做些什么
        config.headers['Authorization'] = sessionStorage.getItem('Authorization');
        return config;
      },
      (error: any) => { 
          // 对请求错误做些什么
        return Promise.reject(error)
      }
    )
    // 响应拦截
    instance.interceptors.response.use(
      (res: any) => {
        // 2xx 范围内的状态码都会触发该函数。
        // 对响应数据做点什么
        let msg = res.data['msg'] || '未知错误,请联系管理员'
        switch (code) {
          case 401:
            msg = '认证失败,无法访问系统资源'
            break
            //......
          case 'default':
            msg = '系统未知错误'
            break
        }
        if (code === 200) {
          return Promise.resolve(res)
        } else {
          //ElMessage.error(msg)
          return Promise.reject(res)
        }
      },
      (error: any) => {
        // 超出 2xx 范围的状态码都会触发该函数
        // 对响应错误做点什么
        return Promise.reject(error)
      }
    )
  }

猜你喜欢

转载自blog.csdn.net/JiangZhengyang7/article/details/129260624