Vue合理配置axios並在專案中進行實際應用?

神奇的程式設計師發表於2019-12-16

送人玫瑰,手有餘香,你是什麼,你的世界就是什麼?

前言

網路上與axios相關的教程、以及原始碼解析有很多,還有健全的官方文件,本篇文章面向於初學axios庫的開發者,目標是快速上手,如果覺得本篇文章幫助到了你,也就達到了這篇文章的目的?

安裝依賴

本文中使用的是Vue CLI3.0,安裝依賴使用vue add命令進行

  • axios安裝
    vue add axios
    # yarn | npm安裝
    yarn add axios | npm install axios
複製程式碼
  • 引用外掛 執行add命令後,CLI會自動幫我們在main.js中引用它,並做一些預設配置。接下來,帶大家看一下,add命令都做了那些事情

    • src下新建了一個plugins資料夾,這個資料夾用於存放Vue引入外掛的相關配置檔案
    • 在plugins資料夾中,新建了axios.js檔案
    • 在package.json檔案中新增了axios的依賴資訊以及版本號(yarn | npm安裝時會自動做這一步)
    • main.js中匯入了axios的配置檔案,方便全域性使用axios
  • 使用外掛

this.axios.${方法名}.then().catch()
// 例子
this.axios.get(url,requestData).then((res)=>{
    // 成功的回撥
}).catch((err)=>{
    // 失敗的回撥
});

/*
    支援所有http請求以及請求取消、併發請求等功能,更多細節以及使用方法移步官方文件
    文件: [axios文件](http://www.axios-js.com/zh-cn/docs/)
*/
複製程式碼

配置axios

接下來回到本文的重點,如何去合理的配置它以提高開發效率。本篇配置基於腳手架建立的axios.js進行修改

  • 建立配置檔案 如果使用腳手架進行安裝axios,將會在在src目錄下查詢plugins資料夾,並在plugins資料夾下建立axios.js檔案。如果使用yarn方式安裝,請手動建立plugins資料夾以及對應的js檔案。

  • 配置檔案程式碼

     "use strict";
     import Vue from 'vue';
     import axios from "axios";
     import store from '../store/index';
     let config = {
     // baseURL在此處省略配置,考慮到專案可能由多人協作完成開發,域名也各不相同,此處通過對api的抽離,域名單獨配置在base.js中
    
      // 請求超時時間
      timeout: 60 * 1000,
      // 跨域請求時是否需要憑證
      // withCredentials: true, // Check cross-site Access-Control
      heards:{
        get:{
          'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
          // 將普適性的請求頭作為基礎配置。當需要特殊請求頭時,將特殊請求頭作為引數傳入,覆蓋基礎配置
        },
        post:{
          'Content-Type': 'application/json;charset=utf-8'
          // 將普適性的請求頭作為基礎配置。當需要特殊請求頭時,將特殊請求頭作為引數傳入,覆蓋基礎配置
        }
      },
      // 在向伺服器傳送請求前,對資料進行處理,axios預設會序列化資料
      // transformRequest:[function(data){
      //
      // }],
      // 在傳遞給 then/catch 前,修改響應資料
      // transformResponse:[function(data){
      //
      // }]
    };
    /**
     * 請求失敗後的錯誤統一處理,當然還有更多狀態碼判斷,根據自己業務需求去擴充套件即可
     * @param {Number} status 請求失敗的狀態碼
     */
    const errorHandle = (status, other) => {
      // 狀態碼判斷
      switch (status) {
          // 401: 未登入狀態,跳轉登入頁
        case 401:
          // 跳轉登入頁
          break;
          // 403 token過期
        case 403:
          // 如果不需要自動重新整理token,可以在這裡移除本地儲存中的token,跳轉登入頁
    
          break;
          // 404請求不存在
        case 404:
          // 提示資源不存在
          break;
        default:
          console.log(other);
      }};
    
    // 建立例項
    const _axios = axios.create(config);
    // 請求攔截器
    _axios.interceptors.request.use(
      function(config) {
        // 從vuex裡獲取token
        const token = store.state.token;
        // 如果token存在就在請求頭裡新增
        token && (config.headers.token = token);
        return config;
      },
      function(error) {
        // Do something with request error
        error.data = {};
        error.data.msg = "伺服器異常";
        return Promise.reject(error);
      }
    );
    
    // 響應攔截器
    _axios.interceptors.response.use(
      function(response) {
       // 清除本地儲存中的token,如果需要重新整理token,在這裡通過舊的token跟伺服器換新token,將新的token設定的vuex中
        if(response.data.code===401){
          localStorage.removeItem("token");
        }
        // 只返回response中的data資料
        return response.data;
      },
      function(error) {
        if(error){
          // 請求已發出,但不在2xx範圍內
          errorHandle(error.status,error.data.msg);
          return Promise.reject(error);
        }else{
          // 斷網
          return Promise.reject(error);
        }
      }
    );
    
    // eslint-disable-next-line no-unused-vars
    Plugin.install = function(Vue, options) {
      Vue.axios = _axios;
      window.axios = _axios;
      Object.defineProperties(Vue.prototype, {
        axios: {
          get() {
            return _axios;
          }
        },
        $axios: {
          get() {
            return _axios;
          }
        },
      });
    };
    
    Vue.use(Plugin);
    // 匯出外掛和_axios
    export default {Plugin,_axios};
    
    複製程式碼
  • 在入口檔案中進行引用

      // main.js
      import './plugins/axios'
    複製程式碼

    這裡進行全域性引用的原因:Vue腳手架推薦的使用方法,方便全域性使用this.axios來訪問。通過配置項建立 axios 例項的方式進行配置封裝。最後將其匯出並掛載到 Vue 的原型上即可,此時,每次修改 axios 配置,只需要修改對應的檔案即可,不會影響到不相關的功能

  • 小結

    現在給大家梳理下,我們對配置檔案做了那些封裝

    • 設定超時時間
    • 請求頭的集中配置
    • 響應失敗後對狀態碼進行統一處理
    • 在請求攔截中新增token
    • 在響應攔截中對token過期進行相應處理
    • api抽離
    • 介面域名抽離

抽離API和域名介面

為什麼要進行API抽離?假設我們所有的請求都在業務程式碼中寫this.$axios.get(),後期介面變更、有新的需求要多傳引數過去,我們就要去業務程式碼裡一個個去找然後進行修改,那將是一件很頭疼的事。接下來帶大家來實現API分離?

  • 在src下建立api資料夾,建立index.js和base.js

    Vue合理配置axios並在專案中進行實際應用?

  • api統一出口:index.js

將api介面根據功能劃分為多個模組,利於多人開發,一個人負責一個模組的開發,方便日後介面的變更,將所有模組在此處引入,將引用暴露出去,然後掛載到Vue原型既可通過this.$api.模組名.方法名進行引用

   /**
    * api統一出口
    * */
   // 網站管理介面
   import websiteManageAPI from './websiteManageAPI';
   // 其他模組介面
   
   // 匯出介面
   export default {
       websiteManageAPI,
       // ...
   }
複製程式碼
  • 模組檔案:websiteManageAPI.js

推薦命名格式為:模組名+APi,此檔案用於將當前模組下的所有請求封裝成物件,在使用時直接呼叫即可

    /*
    * 網站管理介面
    * */
    import services from '../plugins/axios'
    import base from './base'; // 匯入介面域名列表
    const websiteManageAPI = {
        // 登入
        login(params){
            return services._axios.post(`${base.lk}/login`,params);
        },
        // 測試post介面
        postJSON(params){
            return services._axios.post(`${base.lk}/getter/postJSON`,params);
        },
        // 測試get介面
        getJSON(pageNo,pageSize){
            return services._axios.get(`${base.lk}/getter/getJSON`,{params:{pageNo:pageNo,pageSize:pageSize}});
        }
    };
    
    export default websiteManageAPI;
複製程式碼
  • 介面域名檔案:base.js

將每個開發者的介面地址封裝成物件,在模組中進行引用時域名遇到變更,可直接修改此處的配置檔案,快速修改為變更後的域名。

    /*
   * 介面域名管理
   *
   * */
   const base = {
       lk:"https://www.kaisir.cn/user",
       other:"https://kf.kaisir.cn/api"
   };
   
   export default base;
複製程式碼
  • 原型掛載

將暴露出來的介面掛載到原型上,可方便介面的呼叫,當然你也可以按需載入,用到哪個模組的介面在在哪個模組下進行引用。

    // 掛載到原型(main.js)
    Vue.prototype.$api = api;
複製程式碼

實際應用

例如這樣一個場景:後端的所有介面都需要登入後,根據成功登入返回的token進行訪問。後端介面使用shiro+jwt實現介面鑑權和token發放

  • 頁面載入時,從本地儲存中獲取token
    // App.vue,created生命週期
    const token = localStorage.getItem("token");
複製程式碼
  • 判斷token是否存在,如果不存在則獲取
    // 
    if(lodash.isEmpty(token)){
        // 跳轉登入頁:此處僅用於演示,使用者名稱和密碼為固定資料,實際需求為跳轉登入頁面進行授權
        const userInfo = {
          "username":"測試",
          "password":"0x89oikklsa"
        };
        // 呼叫登入api
        this.$api.websiteManageAPI.login(userInfo).then((res)=>{
          // 將token進行儲存並更新到vuex中
          localStorage.setItem("token",res.token);
          this.$store.state.token = res.token;
        });
    }else{
        // 更新vuex中的token
        this.$store.state.token = token;
    }
複製程式碼
  • 執行結果
    Vue合理配置axios並在專案中進行實際應用?
  • 呼叫其他介面,測試請求頭token是否新增成功
    // 測試其他介面能否呼叫成功
    this.$api.websiteManageAPI.getJSON(1,3).then((res)=>{
        console.log("介面呼叫成功");
        console.log(res)
    });
}
複製程式碼
  • 執行結果
    Vue合理配置axios並在專案中進行實際應用?

寫在最後

  • 文中如有錯誤,歡迎在評論區指正,如果這篇文章幫到了你,歡迎點贊和關注?
  • 本文首發於掘金,如需轉載請評論區留言?

相關文章