cancel token
的api在網上找了許多請求的攔截,但不少都是在請求開始時進行數組存儲CancelToken
方法與比對信息,返回後進行處理。按照其代碼實現了一遍,結果發現雙擊兩次能夠實現請求cancel
,但屢次點擊會發生屢次請求的狀況,故思索了一遍緣由。javascript
// req-intercept.js
let requestList = []; // api請求記錄
/** * 將當前請求記錄到緩存中 * @param {any} config 請求的內容 * @param {function} funcCancel 取消請求函數 */
export const add = (config, funcCancel) => {
if (!config) {
return false;
}
let req = genReq(config);
for (let index = 0, len = requestList.length; index < len; index++) {
if (req === requestList[index].req) {
requestList[index].funcCancel();
// requestList.splice(index, 1); // 把這條記錄從數組中移除
// console.log('cancel request:', config.url);
return;
}
}
requestList.push({
req: genReq(config),
funcCancel
});
};
/** * 將請求完成的對象從緩存中移除 * @param {any} config 請求對象 */
export const remove = (config) => {
if (!config) {
return false;
}
let req = genReq(config);
for (let index = 0, len = requestList.length; index < len; index++) {
if (req === requestList[index].req) {
requestList.splice(index, 1); // 把這條記錄從數組中移除
break;
}
}
};
// 當前請求的api是否已有記錄
export const has = (config) => {
if (!config) {
return false;
}
let req = genReq(config);
for (let index = 0, len = requestList.length; index < len; index++) {
if (req === requestList[index].req) {
return true;
}
}
return false;
};
/** * 生成請求記錄對象,方面對比 * @param {object} config 請求對象 */
const genReq = (config) => {
if (!config) {
return '';
}
let arrayReq = [];
arrayReq.push(`url:${config.url},`);
arrayReq.push(`method:${config.method},`);
arrayReq.push(`params:${json2Form(config.params)},`);
arrayReq.push(`header:${json2Form(config.header)}`);
// let key = 'Method: ' + config.method + ',Url: ' + url + ',Data: ' + json2Form(data) + ', header:' + json2Form(header);
return arrayReq.join('');
};
const json2Form = (json) => {
var str = [];
for (var key in json) {
if (key !== 't') {
str.push(encodeURIComponent(key) + '=' + encodeURIComponent(json[key]));
}
}
return str.join('&');
};
複製代碼
// index.js
import axios from 'axios';
import JSONbig from 'json-bigint';
import * as reqIntercept from './req-intercept.js';
let cancelToken = axios.CancelToken;
let gOpts = {};
const JSONbigString = JSONbig({'storeAsString': true});
let axiosNew = axios.create({
transformResponse: [function (data) {
// return JSONbig.parse(data)
// return JSON.parse(data);
// 處理數據中的精度溢出的數字,將溢出的數字轉換成字符串
return JSONbigString.parse(data);
}]
});
function defaultHeader () {
return {};
};
/** * 分析後端返回的錯誤信息 * @param responseHeader 後臺的相應頭對象 */
const analyzeException = (responseHeader) => {
if (responseHeader) {
const errCode = responseHeader['head.err.code'];
const errMsg = responseHeader['head.err.msg'];
return {
errCode,
// errMsg: errMsg ? decodeURIComponent(errMsg) : SERVICE_ERROR_STATUS[errCode]
errMsg: errMsg ? decodeURIComponent(errMsg) : errCode
};
}
};
// 請求攔截器,每一個請求發出以前須要經過此函數處理一遍
axiosNew.interceptors.request.use(function (config) {
config.cancelToken = new cancelToken((c) => {
reqIntercept.add(config, c);
});
config.baseURL = gOpts.baseURL;
// 注入自定義請求頭
config.headers = Object.assign({}, config.headers, defaultHeader());
return config;
}, function (error) {
return Promise.reject(error);
});
// 響應攔截器,從服務端獲取的數據,都統一處理
axiosNew.interceptors.response.use(function (response) {
reqIntercept.remove(response.config); // 在一個ajax響應後再執行一下取消操做,把已經完成的請求從pending中移除
if (response.headers) {
if (response.status === 200) {
return response.data;
} else {
return Promise.reject(analyzeException(response.headers));
}
} else {
// 兼容webpack-dev-server熱加載,攔截器中獲取的response只有消息體,直接返回消息體的內容
return response;
}
}, function (error) {
if (!error.__CANCEL__) {
return Promise.reject(analyzeException(error.response));
}
// return Promise.reject(analyzeException(error.response.headers));
});
const request = (url, params, method = 'GET', headerData = {}) => {
method = method.toUpperCase();
let config = {
url: url,
method: method,
headers: headerData
};
if (method === 'POST' || method === 'PUT') {
Object.assign(config, {
data: params
});
} else {
Object.assign(config, {
params: Object.assign({}, params, {
t: new Date().getTime()
})
});
}
return new Promise((resolve, reject) => {
axiosNew(config).then((data) => {
if (data) {
resolve(data);
} else {
resolve(undefined);
}
}).catch(error => {
reject(new Error(error));
});
});
};
export const axiosInterceptors = (target) => {
target.prototype.responseInterceptors = (response) => {
console.log('responseInterceptors11');
return response;
};
target.prototype.fetch = (url, params, method, headerData = {}) => {
return request(url, params, method, headerData);
};
/** 設置全局配置參數 */
target.prototype.setOpts = (opts) => {
gOpts = opts;
};
};
複製代碼
隨後查找緣由,發如今req-intercept.js
中的add方法中,若是請求的req判斷一致後,會執行cancelToken函數,但隨後也會被終止push;java
/** * 將當前請求記錄到緩存中 * @param {any} config 請求的內容 * @param {function} funcCancel 取消請求函數 */
export const add = (config, funcCancel) => {
if (!config) {
return false;
}
let req = genReq(config);
for (let index = 0, len = requestList.length; index < len; index++) {
if (req === requestList[index].req) {
requestList[index].funcCancel();
// requestList.splice(index, 1); // 把這條記錄從數組中移除
// console.log('cancel request:', config.url);
return;
}
}
requestList.push({
req: genReq(config),
funcCancel
});
};
複製代碼
這樣的請求在我看來是不正確的,很是使人不適。webpack
/** * 將當前請求進行去重 * @param {object} req 當前請求 * @param {array} requestList api請求記錄 * @param {string} key 比對的信息key值 * @param {number} num 比對的個數 */
class repetition {
constructor ({
req,
requestList,
key,
num
}) {
this.requestList = requestList;
this.req = req;
this.requestList.push(req);
this.key = key;
this.num = num || 1;
this.cancelList = [];
}
cancelReq () {
let count = 0;
for (let i = 0; i < this.requestList.length; i++) {
console.log(this.req[this.key], this.requestList[i][this.key]);
if (this.req[this.key] === this.requestList[i][this.key]) {
if (count > 0) {
this.requestList[i].funcCancel();
console.log('請求被釋放');
this.cancelList.push(i);
}
count++;
}
}
for (let j = 0; j < this.cancelList.length; j++) {
this.requestList.splice(this.cancelList[j], 1);
}
this.cancelList = [];
return count;
}
}
/** * 將當前請求記錄到緩存中 * @param {any} config 請求的內容 * @param {function} funcCancel 取消請求函數 */
export const add = (config, funcCancel) => {
if (!config) {
return false;
}
let obj = {
req: genReq(config),
funcCancel
};
let repetit = new repetition({
req: obj,
requestList,
key: 'req'
});
repetit.cancelReq();
// for (let index = 0, len = requestList.length; index < len; index++) {
// if (req === requestList[index].req) {
// console.error('-------執行funcCancel---------');
// requestList[index].funcCancel();
// // requestList.splice(index, 1); // 把這條記錄從數組中移除
// // console.log('cancel request:', config.url);
// return;
// }
// }
};
複製代碼
實驗的結果:ios
如今達到的效果是:相同的接口請求,只有等上個結果請求返回後才能進行下個請求。web
如下是所有代碼:ajax
// index.js
import axios from 'axios';
import JSONbig from 'json-bigint';
import { Message } from 'element-ui';
import { getGlobalConf } from '@/utils/grocer';
// import { APP_ID, SERVICE_ERROR_STATUS } from '@/common/constants';
import * as reqIntercept from './req-intercept.js';
let gOpts = {};
let cancelToken = axios.CancelToken;
const conf = getGlobalConf();
const JSONbigString = JSONbig({'storeAsString': true});
let axiosNew = axios.create({
transformResponse: [function (data) {
// return JSONbig.parse(data)
// return JSON.parse(data);
// 處理數據中的精度溢出的數字,將溢出的數字轉換成字符串
return JSONbigString.parse(data);
}]
});
function defaultHeader () {
return {
// 'apiVersion': '1.0'
// 'zhsession': getZHSessionStore()
};
};
/** * 檢查登陸狀態,若是登陸超時,跳轉到登陸頁面 * @returns 登陸超時返回 false */
const checkLogin = (resData) => {
if (resData && typeof resData === 'string' && resData.indexOf('忘記密碼1') > -1) {
window.location.href = '/base/login';
return false;
}
return true;
};
/** * 分析後端返回的錯誤信息 * @param responseHeader 後臺的相應頭對象 */
const analyzeException = (responseData) => {
if (responseData) {
return {
resultCode: responseData.code,
// errMsg: errMsg ? decodeURIComponent(errMsg) : SERVICE_ERROR_STATUS[errCode]
resultMsg: responseData.code
};
}
};
// 請求攔截器,每一個請求發出以前須要經過此函數處理一遍
axiosNew.interceptors.request.use(function (config) {
if (config.url.indexOf('http://') < 0) {
config.baseURL = conf.baseURL;
}
config.cancelToken = new cancelToken((c) => {
console.log('已添加');
reqIntercept.add(config, c);
});
console.log(3232);
config.baseURL = gOpts.baseURL;
// 注入自定義請求頭
config.headers = Object.assign({}, config.headers, defaultHeader());
return config;
}, function (error) {
return Promise.reject(error);
});
// 響應攔截器,從服務端獲取的數據,都統一處理
axiosNew.interceptors.response.use(function (response) {
reqIntercept.remove(response.config); // 在一個ajax響應後再執行一下取消操做,把已經完成的請求從pending中移除
console.log(response);
if (response.status === 200) {
if (!checkLogin(response.data)) {
return;
}
if (response.config.method.toUpperCase() !== 'GET') {
console.log(response, 'get');
// 兼容企業庫和圈子的數據接口
if (response.data && (response.data.code === 200 || response.data.code === 0 || response.data.errorCode === 0 || response.data.errcode === 0 || response.data.errCode === 0 || response.data.statusCode === '200')) {
Message({
title: '成功',
message: '操做完成',
type: 'success'
});
} else {
if (response.data.statusCode) {
return response;
} else {
let errMsg = response.data.msg || response.data.errmsg || '';
Message({
title: '失敗',
message: errMsg,
type: 'error'
});
throw new Error(errMsg);
}
}
}
if (response.config.method.toUpperCase() === 'POST' && response.data.statusCode) {
console.log(response, 'post');
return response;
}
console.log(response, 'no');
return response.data;
} else {
Message({
title: '失敗',
message: '系統異常,請稍後重試。。',
type: 'error'
});
// return Promise.reject(analyzeException(response));
throw new Error('系統異常,請稍後重試。。');
// return response.data;
}
}, function (error) {
// 判斷是否爲登陸超時。若是登陸超時,跳轉到登陸頁面
if ('response' in error && error.response === undefined) {
window.location.href = '/base/login';
return;
}
if ('message' in error) {
return;
}
// console.log('axiosNew.interceptors.response error', JSON.stringify(error, null, 2));
// return Promise.reject(analyzeException(error.response.headers));
// return Promise.reject(error);
Message({
title: '失敗',
message: '後臺接口異常',
type: 'error'
});
console.log(error, 'error');
throw new Error(error);
});
const req = (url, params, method = 'GET', headerData = {}) => {
return new Promise((resolve, reject) => {
let config = {
url: url,
method: method,
headers: headerData
};
if (method === 'POST' || method === 'PUT' || method === 'DELETE') {
Object.assign(config, {
data: params
});
} else {
Object.assign(config, {
params: Object.assign({}, params, {
t: new Date().getTime()
})
});
};
const arrLink = [
'cms/lottery',
'cms/prize',
'cms/level'
];
const hasLink = (str) => {
let res = false;
str += '';
arrLink.forEach(item => {
if (str.indexOf(item) !== -1) {
res = true;
};
});
return res;
};
axiosNew(config).then((data) => {
console.log(data, '--------------------------------');
if (data) {
let resData;
if ('errorCode' in data && hasLink(config.url)) {
resData = data;
} else {
resData = data.data || data;
}
resolve(resData);
} else {
return false;
// resolve(undefined);
}
}).catch(error => {
reject(new Error(error));
});
});
};
export default req;
複製代碼
// req-intercept.js
let requestList = []; // api請求記錄
/** * 將當前請求進行去重 * @param {object} req 當前請求 * @param {array} requestList api請求記錄 * @param {string} key 比對的信息key值 * @param {number} num 比對的個數 */
class repetition {
constructor ({
req,
requestList,
key,
num
}) {
this.requestList = requestList;
this.req = req;
this.requestList.push(req);
this.key = key;
this.num = num || 1;
this.cancelList = [];
}
cancelReq () {
let count = 0;
for (let i = 0; i < this.requestList.length; i++) {
console.log(this.req[this.key], this.requestList[i][this.key]);
if (this.req[this.key] === this.requestList[i][this.key]) {
if (count > 0) {
this.requestList[i].funcCancel();
console.log('請求被釋放');
this.cancelList.push(i);
}
count++;
}
}
for (let j = 0; j < this.cancelList.length; j++) {
this.requestList.splice(this.cancelList[j], 1);
}
this.cancelList = [];
return count;
}
}
/** * 將當前請求記錄到緩存中 * @param {any} config 請求的內容 * @param {function} funcCancel 取消請求函數 */
export const add = (config, funcCancel) => {
if (!config) {
return false;
}
let obj = {
req: genReq(config),
funcCancel
};
let repetit = new repetition({
req: obj,
requestList,
key: 'req'
});
repetit.cancelReq();
// for (let index = 0, len = requestList.length; index < len; index++) {
// if (req === requestList[index].req) {
// console.error('-------執行funcCancel---------');
// requestList[index].funcCancel();
// // requestList.splice(index, 1); // 把這條記錄從數組中移除
// // console.log('cancel request:', config.url);
// return;
// }
// }
};
/** * 將請求完成的對象從緩存中移除 * @param {any} config 請求對象 */
export const remove = (config) => {
if (!config) {
return false;
}
let req = genReq(config);
for (let index = 0, len = requestList.length; index < len; index++) {
if (req === requestList[index].req) {
console.log('-- removed---');
requestList.splice(index, 1); // 把這條記錄從數組中移除
break;
}
}
};
// 當前請求的api是否已有記錄
export const has = (config) => {
if (!config) {
return false;
}
let req = genReq(config);
for (let index = 0, len = requestList.length; index < len; index++) {
if (req === requestList[index].req) {
return true;
}
}
return false;
};
/** * 生成請求記錄對象,方面對比 * @param {object} config 請求對象 */
const genReq = (config) => {
if (!config) {
return '';
}
let arrayReq = [];
arrayReq.push(`url:${config.url},`);
arrayReq.push(`method:${config.method},`);
arrayReq.push(`params:${json2Form(config.params)},`);
arrayReq.push(`header:${json2Form(config.header)}`);
// let key = 'Method: ' + config.method + ',Url: ' + url + ',Data: ' + json2Form(data) + ', header:' + json2Form(header);
return arrayReq.join('');
};
const json2Form = (json) => {
var str = [];
for (var key in json) {
if (key !== 't') {
str.push(encodeURIComponent(key) + '=' + encodeURIComponent(json[key]));
}
}
return str.join('&');
};
複製代碼