Axios 在 vue 官方推薦後被愈來愈多的人使用,可是不得不說在項目直接使用 axios 實在是繁瑣,每次都要寫一堆的配置,並且將配置寫在業務代碼中十分地不雅,通常在項目中使用的時候都會將其再次封裝,以便更好的使用。可是在網上找了一圈,都沒發現讓我滿意的方案,不是不優雅,就是根本不實用。因而我本身實現了個簡單可是很是實用的封裝。javascript
我我的理想中的請求方案以下:vue
可能大家會問,什麼叫集中管理但去『中心化』集中管理不難理解,可是若是集中到一個文件的話,可能項目初期並無什麼問題,可是一旦項目作大了,這個文件對於維護者來講簡直就是災難,因此須要將一個文件分紅多個文件『集中』管理。java
可是劃分的規則是什麼?以功能模塊劃分。這個在咱們公司的項目中已經有了很好的實踐,如下是文件結構:node
. ├── src | ├── modules | | ├── module1 | | | ├── apis.js | | | └── ... | | ├── module2 | | | ├── apis.js | | | └── ... | | └── ... | ├── api.js | └── ... └── ...
咱們的封裝就 寫在 src/api.js
文件中。webpack
具體配置項的意思這裏就不寫了,詳見官網。baseURL
可根據公司的狀況和環境變量來注入不用的值。ios
import Axios from 'axios'; export const axios = Axios.create({ baseURL: process.env.VUE_APP_API_BASIC_URL, responseType: 'json', // withCredentials: true, headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, validateStatus: status => ((status >= 200 && status < 300) || status === 304) });
請求攔截器中能夠作一些騷操做,這裏就簡單地添加 token
。git
Axios.interceptors.request.use( config => { /*FIXME*/ // 此處根據公司狀況替換獲取 token 的方式 const token = "xxx"; if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }, error => Promise.reject(error); );
require.context
是 webpack 動態引入文件的方法,若是大家公司不使用 webpack 進行打包,可以使用 node 的 fs
模塊。require.context
具體的使用方式見 webpack 官網github
let apisConfig = {}; const apis = {}; const context = require.context(`./modules`, true, /apis\.js$/); context.keys().forEach(key => { const {default: api} = context(key); apisConfig = Object.assign(apisConfig, api); });
直接上代碼:web
Object.keys(apisConfig).forEach(key => { const config = apisConfig[key]; /** * 實際發送請求的方法 * @param restful restful 參數 * @param params 請求參數 * @return {Promise<AxiosResponse<T>>} */ function request(restful, params) { config.method = config.method || 'get'; let parameter = {}; let query = {}; if (config.restful) { const match = config.url.match(/{[^{}]+}/g); if (!config.transform) { if (match && match.length > 0) { match.forEach(str => { str = str.slice(1, -1); if (!restful || Object.prototype.toString.call(restful) !== '[object Object]' || !Object.keys(restful).includes(str)) { let cancel; config.cancelToken = new CancelToken(c => cancel = c); cancel(`${key} 請求中 ${str} 參數未注入`); } else { config.url = config.url.replace(`{${str}}`, restful[str]); } }); config.transform = true; } else { let cancel; config.cancelToken = new CancelToken(c => cancel = c); cancel('你彷佛並不須要 restful,請刪除 restful 屬性,或賦值爲 false'); } } parameter = params; query = arguments[2]; } else { parameter = restful; query = arguments[1]; } if (config.method === 'get' || config.method === 'delete') { config.params = {...parameter, ...query}; } else if (config.method === 'post' || config.method === 'put' || config.method === 'patch') { config.data = parameter; config.params = query; } return axios.request(config); } apis[key] = request; });
這裏解決一個痛點:axios 不支持 restful。至少我翻了官網沒看到有支持 restful,若是有哪位大佬知道 axios 原生支持 restful 的方法,請評論或郵件指導,感謝。json
完整代碼能夠看個人 github 上的項目。
在各個模塊下的 apis.js
文件中寫入如下配置:
export default { getTest: { // 請求的 url url: '/user/{id}', // 請求的方式,默認是 get 方式,可不寫 method:'get' // 是否支持 restful restful: true },
若是有請求的域名和基本配置中的不一致的,可使用絕對 URL,記得帶上網絡協議
在 main.js
中引入,並添加到 window 對象上,這樣就能夠全局使用了
import api from './api'; window.api = api;
使用 window.api
window.api.getTest({userId: 1, id: 2}, {name: 'Tom'}).then((data: any) => { console.log(data); }).catch((e: any) => { Promise.reject(e); });
雖然使用 Promise
能夠簡單地獲取數據和捕獲錯誤,可是若是使用 ES7
中的 async
函數卻不得不 try/catch
,這裏使用大佬的提供一個更加 hack 的方式,詳見 How to write async await without try-catch blocks in Javascript
async getTestData() { const [error, data] = await to(window.api.getTest({userId: 1, id: 2}, {name: 'Tom'})); if(error){ ... } ... }
因爲本人經驗尚淺,可能存在一些 bug,若是發現請及時提出,與君共勉,謝謝。
歡迎轉載,轉載請註明出處:https://blog.kaguramea.me/archives/axios-encapsulation