Axios 實用封裝

Axios 實用封裝

Axios 在 vue 官方推薦後被愈來愈多的人使用,可是不得不說在項目直接使用 axios 實在是繁瑣,每次都要寫一堆的配置,並且將配置寫在業務代碼中十分地不雅,通常在項目中使用的時候都會將其再次封裝,以便更好的使用。可是在網上找了一圈,都沒發現讓我滿意的方案,不是不優雅,就是根本不實用。因而我本身實現了個簡單可是很是實用的封裝。javascript

實現思路

我我的理想中的請求方案以下:vue

  1. 實際請求與請求配置解耦
  2. 請求配置可配置
  3. 請求配置集中管理
  4. 請求配置去『中心化』

可能大家會問,什麼叫集中管理但去『中心化』集中管理不難理解,可是若是集中到一個文件的話,可能項目初期並無什麼問題,可是一旦項目作大了,這個文件對於維護者來講簡直就是災難,因此須要將一個文件分紅多個文件『集中』管理。java

可是劃分的規則是什麼?以功能模塊劃分。這個在咱們公司的項目中已經有了很好的實踐,如下是文件結構:node

.
├── src
|   ├── modules
|   |   ├── module1
|   |   |   ├── apis.js
|   |   |   └── ...
|   |   ├── module2
|   |   |   ├── apis.js
|   |   |   └── ...
|   |   └── ...
|   ├── api.js
|   └── ...
└── ...

咱們的封裝就 寫在 src/api.js 文件中。webpack

添加 axios 基本配置

具體配置項的意思這裏就不寫了,詳見官網。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)
});

添加請求攔截器

請求攔截器中能夠作一些騷操做,這裏就簡單地添加 tokengit

Axios.interceptors.request.use(
    config => {
        /*FIXME*/
        // 此處根據公司狀況替換獲取 token 的方式
        const token = "xxx";
        if (token) {
            config.headers.Authorization = `Bearer ${token}`;
        }
        return config;
    },
    error => Promise.reject(error);
);

獲取不一樣模塊下的 apis

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 上的項目

如何使用

1. 編寫請求配置

在各個模塊下的 apis.js 文件中寫入如下配置:

export default {
    getTest: {
        // 請求的 url
        url: '/user/{id}',
        // 請求的方式,默認是 get 方式,可不寫
        method:'get'
        // 是否支持 restful
        restful: true
    },

若是有請求的域名和基本配置中的不一致的,可使用絕對 URL,記得帶上網絡協議

2. 引入封裝後的 axios

main.js 中引入,並添加到 window 對象上,這樣就能夠全局使用了

import api from './api';

window.api = api;

3. 發送請求

使用 window.api

window.api.getTest({userId: 1, id: 2}, {name: 'Tom'}).then((data: any) => {
    console.log(data);
}).catch((e: any) => {
    Promise.reject(e);
});

4. 讓請求更加 hack

雖然使用 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

相關文章
相關標籤/搜索