vue+axois 封裝請求+攔截器(請求鎖+統一處理錯誤碼)

FannieGirl發表於2020-12-15

 需求

  1.  封裝常用請求
  2.  攔截器-請求鎖
  3.  統一處理錯誤碼

 

一、封裝常用的請求

  解決痛點:不要每一個模組的api都還要寫get,post,patch請求方法。直接將這些常用的方法封裝好。

  解決方案:寫一個類,封裝好常用的請求

  部分原始碼如下

export default class PublicAPI {
    constructor(url) {
        this.url = url;
    }

    get(params, filter) {
        if (Array.isArray(params)) {
            filter = typeof filter === 'object' ? JSON.stringify(filter) : filter;
            let qs = filter ? '?filter=' + filter : '';
            return axios.get(this.url + '/' + params.join('/') + qs);
        }
        params = params || {};
        return axios.get(this.url, { params });
    }

    delete(id) {
        return axios.delete(`${this.url}/${id}`);
    }

    post(params) {
        return axios.post(this.url, params);
    }
   //常用請求 都可以封裝在這裡 }

 

二、攔截器-請求鎖

  解決痛點:限制同一時間發多個同一個請求

  解決方案:利用axios的攔截器 + axios.CancelToken,限制同一個請求多次傳送

  原始碼如下

方案一:簡單款

let pending = []; //宣告一個陣列用於儲存每個ajax請求的取消函式和ajax標識
let CancelToken = axios.CancelToken;
let removePending = (config) => {
    for(let p in pending){
        if(pending[p].u === config.url + '&' + config.method) { //當前請求在陣列中存在時執行函式體
            pending[p].f(); //執行取消操作
            pending.splice(p, 1); //把這條記錄從陣列中移除
        }
    }
}

方案二:複雜款(這個是在掘金上看到的,原連結找不到了)

let pending = {};
/**
 * cancelKey管理器
 *
 * @return {Object} 返回一個物件,物件暴露兩個方法,一個可以獲取本次請求的key,一個是設定本次請求的key
 * @memberof HttpRequest
 */
let cancelKeyManager = () => {
    const expose = {};
    expose.setKey = function setKey(config) {
        const { method, url, params, data } = config;
        expose.key = `${method}|${url}`;
        //expose.key = method === 'get' ? `${expose.key}&${JSON.stringify(params)}` : `${expose.key}&${JSON.stringify(data||{})}`;
    };
    expose.getKey = function getKey() {
        return expose.key;
    };
    return expose;
};

/**
 *處理請求攔截和請求取消
 *
 * @param {object} config axios配置物件
 * @param {boolean} [isCancel=true] 標識是請求取消還是攔截請求
 * @return {object} 返回axios配置物件
 * @memberof HttpRequest
 */
let handleRequestCancel = (config, isCancel = false) => {
    // 設定本次請求的key
    const { setKey, getKey } = cancelKeyManager();
    setKey(config);
    const key = getKey();
    const CancelToken = axios.CancelToken;
    // 取消已經發出去的請求
    if (isCancel) {
        removeRequest(key, true);
        // 設定本次請求的cancelToken
        config.cancelToken = new CancelToken(c => {
            pending[key] = c;
        });
    } else {
        // 攔截本次請求
        config.cancelToken = new CancelToken(c => {
            // 將本次的cancel函式傳進去
            pending[key] = c;
            removeRequest(key, true, c);
        });
    }

    return config;
};

/**
 * 移除請求
 *
 * @param {string} key 標識請求的key
 * @param {boolean} [isRequest=false] 標識當前函式在請求攔截器呼叫還是響應攔截器呼叫
 * @param {function} c cancel函式
 * @memberof HttpRequest
 */
let removeRequest = (key, isRequest = false, c) =>{
    // 請求前先判斷當前請求是否在pending中,如果存在有兩種情況:
    // 1. 上次請求還未響應,本次的請求被判為重複請求,則呼叫cancel方法攔截本次重複請求或者取消上一個請求
    // 2. 上次請求已經響應,在response中被呼叫,清除key
    console.log(key,pending);
    if (pending[key]) {
        if (isRequest) {
            Message.error({
                message: '請求過於頻繁'
            });
        } else {
            // 上一次請求在成功響應後呼叫cancel函式刪除key
            delete pending[key];
        }
    }
};

 

三、統一處理錯誤碼

  解決痛點:每個請求都需要處理錯誤資訊,特別是一些常用的錯誤(堅持能封裝就封裝的思想),當然具體業務處理邏輯這是各自處理啦!

  解決方案:用axios攔截器,將返回來的錯誤統一處理,最常用的就是401 token失效吧!一般是要前後端統一錯誤碼的,固定的錯誤碼做固定的事情!

  部分原始碼如下(感覺只適合部分)

axios.interceptors.response.use(
response => {
return new Promise((resolve, reject) => { //很重要 用promise 接收自定義錯誤碼
let data = response.data;
if (data.code === 'ok') {
return resolve({
data: data.data || data || {},
response: response
});
} else {
switch (data.code) {
case '10500': //自定義code
reject({
response: {
code: '10500',
status: 500,
msg: data.msg
}
});
break;
default:
reject(response);
}
}
});
},error => {}
)

 

總結

  給出的原始碼比較分散,僅提供思路。

  在專案中這麼一套全家桶用下來,十分巴適~~~

  有疑問可以給我留言,我會盡力解答哦

相關文章