需求
- 封裝常用請求
- 攔截器-請求鎖
- 統一處理錯誤碼
一、封裝常用的請求
解決痛點:不要每一個模組的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 => {}
)
總結
給出的原始碼比較分散,僅提供思路。
在專案中這麼一套全家桶用下來,十分巴適~~~
有疑問可以給我留言,我會盡力解答哦