送人玫瑰,手有餘香,你是什麼,你的世界就是什麼?
前言
網路上與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
-
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;
}
複製程式碼
- 執行結果
- 呼叫其他介面,測試請求頭token是否新增成功
// 測試其他介面能否呼叫成功
this.$api.websiteManageAPI.getJSON(1,3).then((res)=>{
console.log("介面呼叫成功");
console.log(res)
});
}
複製程式碼
- 執行結果
寫在最後
- 文中如有錯誤,歡迎在評論區指正,如果這篇文章幫到了你,歡迎點贊和關注?
- 本文首發於掘金,如需轉載請評論區留言?