应用场景:用户发起多个并发请求,但是token现在是失效的,这个时候页面会弹出多个接口返回的token失效的报错信息,很显然这不是我们想要的,如果发现一个接口请求token失效以后,可不可取消掉其他的后续请求,让用户直接去重新登录去,很显然是可以的。
axios取消请求
官方给出的示例如下
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('/user/12345', {
cancelToken: source.token
}).catch(function (thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// 处理错误
}
});
axios.post('/user/12345', {
name: 'new name'
}, {
cancelToken: source.token
})
// 取消请求(message 参数是可选的)
source.cancel('请求取消了');
但是这样处理显然不够便捷,官方还提供了这样的方法,通过传递一个 executor 函数到 CancelToken 的构造函数来创建一个 cancel token
const CancelToken = axios.CancelToken;
let cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
// executor 函数接收一个 cancel 函数作为参数
cancel = c;
})
});
// 取消请求
cancel();
还可以使用同一个 cancel token 或 signal 取消多个请求
const controller = new AbortController();
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('/user/12345', {
cancelToken: source.token,
signal: controller.signal
}).catch(function (thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// 处理错误
}
});
axios.post('/user/12345', {
name: 'new name' }, {
cancelToken: source.token })
// 取消请求 (message 参数是可选的)
source.cancel('Operation canceled by the user.');
// 或
controller.abort(); // 不支持 message 参数
以上这些是官方给出的一些示例,具体到咱们实际项目要怎么用呢,接下来开始
以下采用了官方提供的 通过传递一个 executor 函数到 CancelToken 的构造函数来创建一个cancel token的方案。
首先全局声明一个变量来存储要取消的axios请求,在main.js中声明
Vue.$requestList=[]
// 创建 axios 实例
const request = axios.create({
// API 请求的默认前缀
baseURL: process.env.VUE_APP_API_BASE_URL,
timeout: 90000 // 请求超时时间
})
const CancelToken = axios.CancelToken
// 异常拦截处理器
const errorHandler = (error) => {
if (error.response) {
const data = error.response.data
// 从 localstorage 获取 token
const token = storage.get(token)
if (error.response.status === 401) {
notification.error({
message: '没有权限',
description: '权限校验失败,请重新登录'
})
//这里取消axios请求
Vue.$requestList.forEach(item => {
item()
})
store.dispatch('Logout').then(() => {
//退出登录以后的回调
})
}
if (error.response.status === 500 || error.response.status === 502) {
notification.error({
message: '服务器错误',
description: '服务器内部错误'
})
}
}
if (axios.isCancel(error)) { // 取消请求的情况下,终端Promise调用链
return new Promise(() => {});
} else {
return Promise.reject(error)
}
}
// request interceptor
request.interceptors.request.use(config => {
//通过传递一个 executor 函数到 `CancelToken` 的构造函数来创建一个 cancel token
config.cancelToken = config.cancelToken = new CancelToken(function executor(c) {
// executor 函数接收一个 cancel 函数作为参数
//这里把cancel函数push到全局变量中
Vue.$requestList.push(c)
})
const token = storage.get(token)
// 如果 token 存在
// 让每个请求携带自定义 token 请根据实际情况自行修改
if (token) {
config.headers.common['token'] = token
}
return config
}, errorHandler)
// response interceptor
request.interceptors.response.use(async (response) => {
const token = storage.get(token)
let errCodeArr = [1001, 1004, 1005]
if (response.data.code == 1006) { //用户未登录
notification.error({
message: '没有权限',
description: '权限校验失败,请重新登录'
})
Vue.$requestList.forEach(item => {
item()
})
store.dispatch('Logout').then(() => {
//退出登录的后续回调
})
} else if (errCodeArr.includes(response.data.code)) {
notification.error({
message: response.data.message,
})
}
return response.data
}, errorHandler)
实测查看可以看到后续的请求被取消掉了