如何在V-cli封裝axios

1. 前言

hello,大家好,終于改完bug了?,F(xiàn)在就開始來(lái)填坑了。在上一篇文章如何優(yōu)雅的使用Vuex中提到了使用axios插件封裝的一個(gè)統(tǒng)一的api庫(kù)。這篇文章就告訴大家如何封裝一個(gè)高效且簡(jiǎn)易使用的api接口庫(kù)。

2. 為什么要封裝axios

剛回武漢的時(shí)候,接手一個(gè)新的項(xiàng)目,剛好這個(gè)項(xiàng)目也是用的axios與后臺(tái)進(jìn)行及交互。具體的使用如下:

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);
     }
   });

當(dāng)然這種使用方法是再與后臺(tái)進(jìn)行交互方面是沒(méi)有什么問(wèn)題,但是在接口如果繁多并且不止再一個(gè)路由中使用時(shí),一旦涉及到接口參數(shù)或者接口url地址的修改就會(huì)讓人很崩潰。并且也沒(méi)做統(tǒng)一的錯(cuò)誤返回處理。前前后后接手的人也很多,所以就出現(xiàn)有的錯(cuò)誤是彈窗提示,有的錯(cuò)誤是頁(yè)面上方的message。有的就干脆不給提示。

我當(dāng)時(shí)也有問(wèn)交接的同事為啥不做一下封裝,誰(shuí)知道這位年輕人的一下就站起來(lái),很快啊,上來(lái)就是一個(gè)不知道,翻手一個(gè)沒(méi)必要。我大意了,還沒(méi)來(lái)得及反駁,他人就溜了。為了后面自己不再踩坑,我就開始著手進(jìn)行接口封裝。

3. 如何封裝axios

我這篇文章主要講解如何封裝axios,前提是你已經(jīng)熟悉了如何在v-cli腳手架中使用axios。還不了解的小伙伴可以移步axios官方文檔中學(xué)習(xí)axios的具體使用。

3-1. 修改基礎(chǔ)配置

  • 首先我們通過(guò)npm install axios命令下載axios插件
  • 然后在V-cli項(xiàng)目的main.js中引入
import axios from "axios";
Vue.prototype.$axios = axios;
  • 因?yàn)槲覀円诹硗獾?code>js使用到$axios,所以這里要對(duì)main.js做一下修改,讓我們方便在其他非vue的文件中使用到Vue的實(shí)例。
export const app = new Vue({
  router,
  store,
  render: h => h(App)
}).$mount("#app");
  • 在其他文件中使用
// 這里的app就是Vue的實(shí)例了。
import { app } from "../main";

3.2. 創(chuàng)建api.js接口庫(kù)

3.2-1. 我們先在src文件夾下新增utils文件夾,新建api.js文件,編輯該文件

// 引入Vue實(shí)例對(duì)象
import { app } from "../main";
// 設(shè)置請(qǐng)求次數(shù)
let seq = 0;
// 設(shè)置基礎(chǔ)的統(tǒng)一接口方法
function axiosFn(options) {
  const config = {
    // 設(shè)置請(qǐng)求頭和默認(rèn)請(qǐng)求方式
    // 默認(rèn)為get請(qǐng)求
    method: "get",
    // 設(shè)置請(qǐng)求頭方式
    headers: {
      "Content-Type": "application/json;charset=utf-8",
    }
  };
  // 這里是對(duì)傳入的基礎(chǔ)配置進(jìn)行處理
  for (const k in options) {
    if (k !== "param" && options.hasOwnProperty(k)) {
      config[k] = options[k];
    }
  }
  // 設(shè)置不同請(qǐng)求的參數(shù)
  .....
}

第一步主要是設(shè)置基礎(chǔ)的配置,包括請(qǐng)求頭請(qǐng)求方式的設(shè)置。

3.2-2. 根據(jù)請(qǐng)求方式和請(qǐng)求頭的不同設(shè)置不同傳參方式

// 設(shè)置不同請(qǐng)求的參數(shù)
if (
  config.method === "post"
  || config.method === "put"
  || config.method === "delete"
) {
  // 處理formData數(shù)據(jù)上傳
  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;
  }
  // 請(qǐng)求頭為application/json的請(qǐng)求參數(shù)傳遞
  if (config.headers["Content-Type"] === "application/json;charset=utf-8") {
    config["data"] = options.param;
  }
  // 請(qǐng)求頭為application/x-www-form-urlencoded的請(qǐng)求參數(shù)傳遞
  if (config.headers["Content-Type"] === "application/x-www-form-urlencoded") {
    let postData = "";
    for (const key in options.param) {
      // 設(shè)置傳參為數(shù)組時(shí)使用jsonStringfy方法轉(zhuǎn)字符串
      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") {
  // 有可能是字符串這里暫時(shí)先寫非全等
  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"];
}
// 攔截請(qǐng)求結(jié)果
.....

注意:這里的代碼本來(lái)是沒(méi)有這么復(fù)雜的,最開始只是設(shè)置最基礎(chǔ)的get,post請(qǐng)求參數(shù)。后來(lái)因?yàn)檫@個(gè)api庫(kù)被他們拿去用到各個(gè)項(xiàng)目中。出現(xiàn)了一大堆的問(wèn)題。但是他們自己又不會(huì)針對(duì)項(xiàng)目作出對(duì)應(yīng)的修改。一出問(wèn)題就噴我封裝的不對(duì),難用。我又不能和他意氣用事。只有一張圖表達(dá)我的心情。

WechatIMG19.jpeg

咳咳,回到上述代碼中,這里get請(qǐng)求涉及到的處理不多,主要是其他的請(qǐng)求和請(qǐng)求頭的不同的處理

  • get請(qǐng)求處理:主要是對(duì)params參數(shù)中數(shù)組對(duì)象進(jìn)行JSON.stringify轉(zhuǎn)碼就好了。這個(gè)是我們這邊的與后臺(tái)約定的統(tǒng)一處理方法。大家如果沒(méi)有這方面的需求可以不加這層判斷。
  • post/put/delete 請(qǐng)求處理:這里主要是對(duì)不同的請(qǐng)求頭進(jìn)行處理。典型的處理是針對(duì)上傳文件的處理。通過(guò)這層處理后,我們?cè)诼?lián)調(diào)上傳接口時(shí),就不用使用new FormData()去包裝我們的上傳參數(shù)了。其它兩種也是常用的請(qǐng)求頭判斷和處理。這個(gè)就看具體的使用項(xiàng)目了。
    3.2-3. 設(shè)置axios攔截器
// 攔截請(qǐng)求結(jié)果
app.$axios.interceptors.response.use(
  function(response) {
    response.seq = seq;
    // 請(qǐng)求成功返回response
    if (response.status === 200) {
      if (response.data.code == 200) {
        return response;
      } else {
        return Promise.reject(response.data);
      }
      return response;
    }
  },
  function(error) {
    //判斷請(qǐng)求超時(shí)
    if (
      error.code === "ECONNABORTED"
      && error.message.indexOf("timeout") !== -1
    ) {
      app.$message.error("請(qǐng)求超時(shí),請(qǐng)刷新頁(yè)面重試!");
      return;
    }
    error.seq = seq;
    return Promise.reject(error);
  }
);
seq++;
// return axios的new promise對(duì)象
return app.$axios(config).then(response => response.data);

注意點(diǎn):

  • 這里的app就是main.jsexport出來(lái)的Vue實(shí)例。
  • 超時(shí)的判斷的錯(cuò)誤碼要和后臺(tái)溝通好。
  • 最后把設(shè)置好的參數(shù)的axios方法return出去。

4. 如何使用封裝好的axios

4.1 export需要使用的接口

611605691090_.pic_hd.jpg

上圖是我們常用的登出接口,文件上傳接口,獲取用戶列表接口。

4.2 頁(yè)面中調(diào)用

image.png
image.png

這里需要注意2點(diǎn)

  1. notifyErrorremoveEmptyProp分別是處理接口返回錯(cuò)誤信息的處理函數(shù),以及移除空的篩選列表篩選參數(shù)的方法。notifyError我們馬上介紹。而這個(gè)removeEmptyProp等我下次bug改完的。O(∩_∩)O。
  2. finallyPromise原型上的方法具體使用是和then,catch一致。這里我用它來(lái)處理無(wú)論接口請(qǐng)求成功或者失敗都關(guān)閉表格的加載loading
    tipsPromise的用法詳解我先挖個(gè)坑。下次記起來(lái)就來(lái)填。

4.3 接口錯(cuò)誤信息統(tǒng)一處理函數(shù)

image.png
// 引入錯(cuò)誤信息描述碼
import {
  ERR_NET_FAIL,
  ERR_API_NO_LOGIN,
  message
} from "@/config/error";
// 統(tǒng)一錯(cuò)誤處理接口
export function notifyError(err) {
  if (err.code) {
    // 登錄超時(shí)返回登錄頁(yè)面
    if (err.code === ERR_API_NO_LOGIN) {
      // 處理3個(gè)接口同時(shí)調(diào)用超時(shí)的問(wèn)題
      if (app.$route.name === "SignIn") {
        return;
      }
      app.$message.error("登錄超時(shí),請(qǐng)重新登錄!");
      app.$router.replace("/SignIn");
    } else if (err.code === ERR_NET_FAIL) {
      // 這里的Alert為封裝的插件彈窗
      app.$Alert(message[ERR_NET_FAIL]);
    } else {
      // 其它狀態(tài)嗎輸出錯(cuò)誤提示
      app.$Alert(err.message || message[ERR_NET_FAIL]);
    }
  } else {
    app.$message.error(message[ERR_NET_FAIL]);
  }
}

這里沒(méi)有啥子好講了,就是通過(guò)不同的code碼來(lái)執(zhí)行不同的操作,彈窗顯示錯(cuò)誤信息登錄超時(shí)跳轉(zhuǎn)登錄頁(yè)面的一些處理。

4. 結(jié)語(yǔ)

終于擼完了,希望這篇文章能幫助到正在使用axios的你。

最后,喜歡的話請(qǐng)點(diǎn)個(gè)贊唄????。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容