使用cancelToken取消请求
本文介绍使用cancelToken取消axios的请求使用方法import Vue from 'vue';import Axios from 'axios';import { Promise } from 'es6-promise';import user from '../store/modules/user'import server from '../config/hostConfig'Ax
本文介绍使用cancelToken取消axios的请求
- 使用方法
import Vue from 'vue';
import Axios from 'axios';
import { Promise } from 'es6-promise';
import user from '../store/modules/user'
import server from '../config/hostConfig'
Axios.defaults.timeout = 45000; // 45s
// Axios.defaults.baseURL = server.target;
var CancelToken = Axios.CancelToken;
//配置取消数组
const urls = ['/api/test']
let pending = []
let removePending = (ever) => {
for(let p in pending){
if(pending[p].u === ever.url + '&' + ever.method) { //当当前请求在数组中存在时执行函数体
pending[p].f(); //执行取消操作
pending.splice(p, 1); //把这条记录从数组中移除
}
}
}
Axios.interceptors.request.use(function(config) {
// Do something before request is sent
//change method for get
if (config['MSG']) {
Vue.prototype.$showLoading(config['MSG']);
} else {
if (!config['NoLoading']) {
// Vue.prototype.$showLoading();
}
}
removePending(config); //在一个ajax发送前执行一下取消操作
if(urls.includes(config.url)){
config.cancelToken = new CancelToken((c) =>{ // executor 函数接收一个 cancel 函数作为参数
// 这里的ajax标识我是用请求地址&请求方式拼接的字符串,当然你可以选择其他的一些方式
pending.push({ u: config.url + '&' + config.method, f: c });
})
}
if (user.state.token) { //用户登录时每次请求将token放入请求头中sso_token
config.headers["sso_token"] = user.state.token;
//config.headers["DZSWJ_TGC"] = user.state.token;
if(config.url.indexOf('?') !== -1){
config.url = config.url + '&sso_token='+user.state.token
}else{
config.url = config.url + '?sso_token='+user.state.token
}
}
if (user.state.loginToken) { //用户登录时每次请求将token放入请求头中
config.headers["sso_token"] = user.state.loginToken;
if(config.url.indexOf('?') !== -1){
config.url = config.url + '&sso_token='+user.state.token
}else{
config.url = config.url + '?sso_token='+user.state.token
}
}
if (config['Content-Type'] === 'application/x-www-form-urlencoded;') { //默认发application/json请求,如果application/x-www-form-urlencoded;需要使用transformRequest对参数进行处理
/*config['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';*/
config.headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
config['transformRequest'] = function(obj) {
var str = [];
for (var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&")
};
}
//config.header['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
return config;
}, function(error) {
// Do something with request error
Vue.$vux.loading.hide()
return Promise.reject(error);
});
Axios.interceptors.response.use(
response => {
removePending(response.config)
if (response.config['Content-Type'] != 'multipart/form-data;') { //图片上传不关闭遮罩,由业务处理
Vue.$vux.loading.hide();
}
if(response.data == '会话结束,请重新登录!'){
return {message:'会话结束,请重新登录!'}
}
return response.data;
},
error => {
Vue.$vux.loading.hide();
if (Axios.isCancel(error)) {
console.log(error.message);
return
}
if (error.response) {
switch (error.response.status) {
case 404:
Vue.prototype.$alert("404未找到请求的资源");
break;
default:
Vue.prototype.$alert('网络错误');
}
} else if (error instanceof Error) {
console.error(error.message);
} else {
Vue.prototype.$alert(error.returnMsg);
}
return Promise.reject(error.response.data);
});
export default Vue.prototype.$http = Axios;
如上代码所示。在请求拦截器中配置cancelToken。通过new CancelToken把取消函数放到pending数组中。
取消请求函数如下,当url与方法相同时会执行取消操作。达到取消重复请求的目的,效果如下图
我们配置了test请求的重复处理。那么连续发送test请求的时候就会取消上一次还没响应过来的请求。test2请求不处理,那么就不会取消test2请求。
let removePending = (ever) => {
for(let p in pending){
if(pending[p].u === ever.url + '&' + ever.method) { //当当前请求在数组中存在时执行函数体
pending[p].f(); //执行取消操作
pending.splice(p, 1); //把这条记录从数组中移除
}
}
}
响应成功之后需要移除取消请求函数。在响应拦截器中判断异常是否为取消请求,是的话取消之前异常处理流程
error => {
Vue.$vux.loading.hide();
if (Axios.isCancel(error)) { //判断异常是否为取消请求导致
console.log(error.message);
return
}
if (error.response) {
switch (error.response.status) {
case 404:
Vue.prototype.$alert("404未找到请求的资源");
break;
default:
Vue.prototype.$alert('网络错误');
}
} else if (error instanceof Error) {
console.error(error.message);
} else {
Vue.prototype.$alert(error.returnMsg);
}
return Promise.reject(error.response.data);
}
- 原理简析
为何配置了cancelToken能达到取消请求的目的呢?
原因在axios源码的xhr.js发送请求部分有如下判断:
if (config.cancelToken) {
// Handle cancellation
config.cancelToken.promise.then(function onCanceled(cancel) {
if (!request) {
return;
}
request.abort();
reject(cancel);
// Clean up request
request = null;
});
}
可以看到这里配置了cancelToken会进行一个判断。当promise状态变为resolve的时候会调用abort方法去取消请求。
那么如何让这个promise的状态变为resolve呢?见CancelToken.js下的如下代码:
function CancelToken(executor) {
if (typeof executor !== 'function') {
throw new TypeError('executor must be a function.');
}
var resolvePromise;
this.promise = new Promise(function promiseExecutor(resolve) {
resolvePromise = resolve;
});
var token = this;
executor(function cancel(message) {
if (token.reason) {
// Cancellation has already been requested
return;
}
token.reason = new Cancel(message);
resolvePromise(token.reason);
});
}
当我们new CancelToken的时候会把executor的回调函数cancel传出,上文我们用pending数组保存了这个cancel函数。cancel函数可以调用到resolvePromise改变promise的状态为resolve。然后便会进入到上文中的then回调函数中进行请求取消。
更多推荐
所有评论(0)