在项目当中,一般请求接口我们会用axios进行统一处理,有时候在页面当中会遇到多次请求同一个接口。如果我们在第2次请求同一个接口时,第一次发送的接口请求还没有得到服务器的响应时,就可以把第一次的接口请求取消掉,这样可以减轻http服务的请求压力。
那么,我们怎么判断2次请求是否相同呢?一般当2个请求的接口地址,请求方式,请求参数都一致时,我们就认为这2个请求相同。因此,我们可以使用一个函数来根据请求信息,生成一个key
generateReqKey:用于根据当前请求的信息,生成请求 Key;
// generateReqKey:用于根据当前请求的信息,生成请求 Key;
function generateReqKey(config) {
const { method, url, params, data } = config;
return [method, url, qs.stringify(params), qs.stringify(data)].join("&");
}
addPendingRequest:用于把当前请求信息添加到pendingRequest对象中;
// addPendingRequest:用于把当前请求信息添加到pendingRequest对象中;
const pendingRequest = new Map();
function addPendingRequest(config) {
const requestKey = generateReqKey(config);
config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {
if (!pendingRequest.has(requestKey)) {
pendingRequest.set(requestKey, cancel);
}
});
}
removePendingRequest:检查是否存在重复请求,若存在则取消已发的请求。
// removePendingRequest:检查是否存在重复请求,若存在则取消已发的请求。
function removePendingRequest(config) {
const requestKey = generateReqKey(config);
if (pendingRequest.has(requestKey)) {
const cancelToken = pendingRequest.get(requestKey);
cancelToken(requestKey);
pendingRequest.delete(requestKey);
}
}
具体在axios的封装中的使用方法:
import {addPendingRequest,removePendingRequest} from '@/util/http'; // 引入添加请求和取消请求
在http request拦截中
//http request拦截
axios.interceptors.request.use(config => {
removePendingRequest(config); // 检查是否存在重复请求,若存在则取消已发的请求
addPendingRequest(config); // 把当前请求信息添加到pendingRequest对象中
return config
}, error => {
return Promise.reject(error)
});
在http response 拦截中
//http response 拦截
axios.interceptors.response.use(res => {
removePendingRequest(res.config); // 从pendingRequest对象中移除请求
return res;
}, error => {
NProgress.done();
removePendingRequest(error.config || {}); // 从pendingRequest对象中移除请求
if (axios.isCancel(error)) {
console.log("已取消的重复请求:" + error.message);
} else {
// 添加异常处理
console.log(error)
}
return Promise.reject(new Error(error));
});
完整的代码如下:
1、先单独写个http.js文件,用来写generateReqKey,addPendingRequest,removePendingRequest 三个函数
http.js
import axios from 'axios';
import qs from 'qs'
// generateReqKey:用于根据当前请求的信息,生成请求 Key;
function generateReqKey(config) {
const { method, url, params, data } = config;
return [method, url, qs.stringify(params), qs.stringify(data)].join("&");
}
// addPendingRequest:用于把当前请求信息添加到pendingRequest对象中;
const pendingRequest = new Map();
function addPendingRequest(config) {
const requestKey = generateReqKey(config);
config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {
if (!pendingRequest.has(requestKey)) {
pendingRequest.set(requestKey, cancel);
}
});
}
// removePendingRequest:检查是否存在重复请求,若存在则取消已发的请求。
function removePendingRequest(config) {
const requestKey = generateReqKey(config);
if (pendingRequest.has(requestKey)) {
const cancelToken = pendingRequest.get(requestKey);
cancelToken(requestKey);
pendingRequest.delete(requestKey);
}
}
export {
addPendingRequest,
removePendingRequest,
}
2、在封装的axios.js文件中使用
axios.js
/**
* 全站http配置
*
* axios参数说明
* isSerialize是否开启form表单提交
* isToken是否需要token
*/
import axios from 'axios';
import store from '@/store/';
import router from '@/router/router';
import {serialize} from '@/util/util';
import {getToken,getDsToken} from '@/util/auth';
import {Message} from 'element-ui';
import website from '@/config/website';
import {Base64} from 'js-base64';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
import {addPendingRequest,removePendingRequest} from '@/util/http'; // 引入添加请求和取消请求
//默认超时时间
axios.defaults.timeout = 60000;
//返回其他状态码
axios.defaults.validateStatus = function (status) {
return status >= 200 && status <= 500;
};
//跨域请求,允许保存cookie
axios.defaults.withCredentials = false;
// NProgress 配置
NProgress.configure({
showSpinner: false
});
//http request拦截
axios.interceptors.request.use(config => {
//开启 progress bar
!config.noNProgress && NProgress.start();
const meta = (config.meta || {});
const isToken = meta.isToken === false;
config.headers['Authorization'] = `Basic ${Base64.encode(`${website.clientId}:${website.clientSecret}`)}`;
//让每个请求携带token
if (getToken() && !isToken) {
config.headers[website.tokenHeader] = 'bearer ' + getToken()
}
config.headers.token = getDsToken();
config.headers.language = 'ZH_CN'
//headers中配置text请求
if (config.text === true) {
config.headers["Content-Type"] = "text/plain";
}
//headers中配置serialize为true开启序列化
if ((config.method === 'post'||config.method === 'put') && meta.isSerialize === true) {
config.data = serialize(config.data);
}
axios.defaults.timeout = config.timeout || 20000
removePendingRequest(config); // 检查是否存在重复请求,若存在则取消已发的请求
addPendingRequest(config); // 把当前请求信息添加到pendingRequest对象中
return config
}, error => {
return Promise.reject(error)
});
//http response 拦截
axios.interceptors.response.use(res => {
//关闭 progress bar
NProgress.done();
//获取状态码
const status = res.data.code || res.status;
const statusWhiteList = website.statusWhiteList || [];
const message = res.data.msg || res.data.error_description || '未知错误';
//如果在白名单里则自行catch逻辑处理
if (statusWhiteList.includes(status)) return Promise.reject(res);
//如果是401则跳转到登录页面
if (status === 401)store.dispatch('FedLogOut').then(() => router.push({path: '/login'}));
// 如果请求为非200否者默认统一处理
if (status !== 200&&status!== 201) {
// 处理特殊的响应返回
if(res.config.responseType=="blob"){
const reader = new FileReader()
reader.readAsText(res.data)
reader.onload = e => {
const { msg } = JSON.parse(reader.result)
this.$message.error(msg)
}
return res
}
Message({
message: message,
type: 'error'
});
return Promise.reject(new Error(message))
}
removePendingRequest(res.config); // 从pendingRequest对象中移除请求
return res;
}, error => {
NProgress.done();
removePendingRequest(error.config || {}); // 从pendingRequest对象中移除请求
if (axios.isCancel(error)) {
console.log("已取消的重复请求:" + error.message);
} else {
// 添加异常处理
console.log(error)
}
return Promise.reject(new Error(error));
});
export default axios;