如何在V-cli封装axios

1. 前言

hello,大家好,终于改完bug了。现在就开始来填坑了。在上一篇文章如何优雅的使用Vuex中提到了使用axios插件封装的一个统一的api库。这篇文章就告诉大家如何封装一个高效且简易使用的api接口库。

2. 为什么要封装axios

刚回武汉的时候,接手一个新的项目,刚好这个项目也是用的axios与后台进行及交互。具体的使用如下:

this.$axios.post(
   "/flow/getSchedule",
   this.$qs.stringify({
   userId: sessionStorage.getItem("userId"),
   pageNumber: pageNumber,
    pageSize: 4
   }))
   .then(resp => {
     this.tableData = resp.data.data;
     if (resp.data.data && resp.data.data.totalRow) {
       sessionStorage.setItem("scheduleCount", resp.data.data.totalRow);
     }
   });

当然这种使用方法是再与后台进行交互方面是没有什么问题,但是在接口如果繁多并且不止再一个路由中使用时,一旦涉及到接口参数或者接口url地址的修改就会让人很崩溃。并且也没做统一的错误返回处理。前前后后接手的人也很多,所以就出现有的错误是弹窗提示,有的错误是页面上方的message。有的就干脆不给提示。

我当时也有问交接的同事为啥不做一下封装,谁知道这位年轻人的一下就站起来,很快啊,上来就是一个不知道,翻手一个没必要。我大意了,还没来得及反驳,他人就溜了。为了后面自己不再踩坑,我就开始着手进行接口封装。

3. 如何封装axios

我这篇文章主要讲解如何封装axios,前提是你已经熟悉了如何在v-cli脚手架中使用axios。还不了解的小伙伴可以移步axios官方文档中学习axios的具体使用。

3-1. 修改基础配置

  • 首先我们通过npm install axios命令下载axios插件
  • 然后在V-cli项目的main.js中引入
import axios from "axios";
Vue.prototype.$axios = axios;
  • 因为我们要在另外的js使用到$axios,所以这里要对main.js做一下修改,让我们方便在其他非vue的文件中使用到Vue的实例。
export const app = new Vue({
  router,
  store,
  render: h => h(App)
}).$mount("#app");
  • 在其他文件中使用
// 这里的app就是Vue的实例了。
import { app } from "../main";

3.2. 创建api.js接口库

3.2-1. 我们先在src文件夹下新增utils文件夹,新建api.js文件,编辑该文件

// 引入Vue实例对象
import { app } from "../main";
// 设置请求次数
let seq = 0;
// 设置基础的统一接口方法
function axiosFn(options) {
  const config = {
    // 设置请求头和默认请求方式
    // 默认为get请求
    method: "get",
    // 设置请求头方式
    headers: {
      "Content-Type": "application/json;charset=utf-8",
    }
  };
  // 这里是对传入的基础配置进行处理
  for (const k in options) {
    if (k !== "param" && options.hasOwnProperty(k)) {
      config[k] = options[k];
    }
  }
  // 设置不同请求的参数
  .....
}

第一步主要是设置基础的配置,包括请求头请求方式的设置。

3.2-2. 根据请求方式和请求头的不同设置不同传参方式

// 设置不同请求的参数
if (
  config.method === "post"
  || config.method === "put"
  || config.method === "delete"
) {
  // 处理formData数据上传
  if (config.headers["Content-Type"] === "multipart/form-data") {
    let formData = new FormData();
    Object.keys(options.param).forEach(key => {
      formData.append(key, options.param[key]);
    });
    config["data"] = formData;
  }
  // 请求头为application/json的请求参数传递
  if (config.headers["Content-Type"] === "application/json;charset=utf-8") {
    config["data"] = options.param;
  }
  // 请求头为application/x-www-form-urlencoded的请求参数传递
  if (config.headers["Content-Type"] === "application/x-www-form-urlencoded") {
    let postData = "";
    for (const key in options.param) {
      // 设置传参为数组时使用jsonStringfy方法转字符串
      if (
        Object.prototype.toString.apply(options.param[key])
        === "[object Array]"
        || Object.prototype.toString.apply(options.param[key])
        === "[object Object]"
      ) {
        options.param[key] = JSON.stringify(options.param[key]);
      }
      postData
        += encodeURIComponent(key)
        + "="
        + encodeURIComponent(options.param[key])
        + "&";
    }
    config["data"] = postData;
  }
} else if (config.method === "get") {
  // 有可能是字符串这里暂时先写非全等
  if (options["param"] != undefined || options["param"] != null) {
    Object.keys(options["param"]).forEach(v => {
      if (
        Object.prototype.toString.apply(options["param"][v])
        === "[object Array]"
        || Object.prototype.toString.apply(options.param[v])
        === "[object Object]"
      ) {
        options["param"][v] = JSON.stringify(options["param"][v]);
      }
    });
  }
  config["params"] = options["param"];
}
// 拦截请求结果
.....

注意:这里的代码本来是没有这么复杂的,最开始只是设置最基础的getpost请求参数。后来因为这个api库被他们拿去用到各个项目中。出现了一大堆的问题。但是他们自己又不会针对项目作出对应的修改。一出问题就喷我封装的不对,难用。我又不能和他意气用事。只有一张图表达我的心情。

WechatIMG19.jpeg

咳咳,回到上述代码中,这里get请求涉及到的处理不多,主要是其他的请求和请求头的不同的处理

  • get请求处理:主要是对params参数中数组对象进行JSON.stringify转码就好了。这个是我们这边的与后台约定的统一处理方法。大家如果没有这方面的需求可以不加这层判断。
  • post/put/delete 请求处理:这里主要是对不同的请求头进行处理。典型的处理是针对上传文件的处理。通过这层处理后,我们在联调上传接口时,就不用使用new FormData()去包装我们的上传参数了。其它两种也是常用的请求头判断和处理。这个就看具体的使用项目了。
    3.2-3. 设置axios拦截器
// 拦截请求结果
app.$axios.interceptors.response.use(
  function(response) {
    response.seq = seq;
    // 请求成功返回response
    if (response.status === 200) {
      if (response.data.code == 200) {
        return response;
      } else {
        return Promise.reject(response.data);
      }
      return response;
    }
  },
  function(error) {
    //判断请求超时
    if (
      error.code === "ECONNABORTED"
      && error.message.indexOf("timeout") !== -1
    ) {
      app.$message.error("请求超时,请刷新页面重试!");
      return;
    }
    error.seq = seq;
    return Promise.reject(error);
  }
);
seq++;
// return axios的new promise对象
return app.$axios(config).then(response => response.data);

注意点:

  • 这里的app就是main.jsexport出来的Vue实例。
  • 超时的判断的错误码要和后台沟通好。
  • 最后把设置好的参数的axios方法return出去。

4. 如何使用封装好的axios

4.1 export需要使用的接口

611605691090_.pic_hd.jpg

上图是我们常用的登出接口,文件上传接口,获取用户列表接口。

4.2 页面中调用

image.png
image.png

这里需要注意2点

  1. notifyErrorremoveEmptyProp分别是处理接口返回错误信息的处理函数,以及移除空的筛选列表筛选参数的方法。notifyError我们马上介绍。而这个removeEmptyProp等我下次bug改完的。O(∩_∩)O。
  2. finallyPromise原型上的方法具体使用是和thencatch一致。这里我用它来处理无论接口请求成功或者失败都关闭表格的加载loading
    tipsPromise的用法详解我先挖个坑。下次记起来就来填。

4.3 接口错误信息统一处理函数

image.png
// 引入错误信息描述码
import {
  ERR_NET_FAIL,
  ERR_API_NO_LOGIN,
  message
} from "@/config/error";
// 统一错误处理接口
export function notifyError(err) {
  if (err.code) {
    // 登录超时返回登录页面
    if (err.code === ERR_API_NO_LOGIN) {
      // 处理3个接口同时调用超时的问题
      if (app.$route.name === "SignIn") {
        return;
      }
      app.$message.error("登录超时,请重新登录!");
      app.$router.replace("/SignIn");
    } else if (err.code === ERR_NET_FAIL) {
      // 这里的Alert为封装的插件弹窗
      app.$Alert(message[ERR_NET_FAIL]);
    } else {
      // 其它状态吗输出错误提示
      app.$Alert(err.message || message[ERR_NET_FAIL]);
    }
  } else {
    app.$message.error(message[ERR_NET_FAIL]);
  }
}

这里没有啥子好讲了,就是通过不同的code码来执行不同的操作,弹窗显示错误信息登录超时跳转登录页面的一些处理。

4. 结语

终于撸完了,希望这篇文章能帮助到正在使用axios的你。

最后,喜欢的话请点个赞呗❤️❤️。

你可能感兴趣的:(如何在V-cli封装axios)