Axios取消请求,以及全局取消请求封装
前提准备
首先编写一个测试接口,模拟接口延迟返回,请求5秒后再返回结果
使用 node + koa
来实现
const Router = require("koa-router");
const router = new Router();router.get("/getLongData", async (ctx, res) => {// 获取get请求的参数// console.log(ctx.query);await new Promise((resolve) => {setTimeout(() => {resolve();}, 5000);});ctx.body = {code: 200,message: "请求成功!",};
});module.exports = router;
AbortController
使用 AbortController
AbortController
是一个浏览器提供的 API,用于取消正在进行的异步操作,如 Fetch 请求或 Axios 请求。你可以创建一个 AbortController
实例,并在 Axios 请求配置中通过 signal 属性传递它。
import axios from 'axios';const controller = new AbortController();axios.get('/foo/bar', {signal: controller.signal
}).then(response => {// 处理响应
}).catch(error => {if (error.name === 'AbortError') {console.log('请求被取消');} else {console.error('发生了一个错误:', error);}
});// 取消请求
controller.abort();
CancelToken
CancelToken
是 Axios 自带的一个类,用于实现请求取消功能。你需要创建一个 CancelToken
实例,并在请求配置中通过 cancelToken 属性传递它。
import axios from 'axios';
import CancelToken from 'axios/cancelToken';let cancel;// 发起请求
axios.get('/foo/bar', {cancelToken: new CancelToken(c => cancel = c)
}).then(response => {// 处理响应
}).catch(error => {if (axios.isCancel(error)) {console.log('请求被取消');} else {console.error('发生了一个错误:', error);}
});// 取消请求
if (cancel) {cancel('取消请求的原因');
}
全局取消请求封装
新建一个 globalCancelToken.js
// 最新的一个请求
let cancel = null// 所有请求
let cancelTokenList = []function setToken(cancelToken) {cancel = cancelTokencancelTokenList.push(cancelToken)
}function cancelToken() {cancel && cancel()cancelTokenList.pop()
}function clearAllToken() {while (cancelTokenList.length > 0) {let cancel = cancelTokenList.pop()console.log(cancel, 'cancel')cancel && cancel()}
}export {setToken,cancelToken,clearAllToken,
}
这个文件中定义了一个变量,一个数组,cancelTokenList 用于存放每一次请求所对应的 cancelToken
在请求拦截器中添加取消请求的配置,相应拦截器中判断错误类型是否为取消请求
import { setToken } from '@/utils/globalCancelToken.js'// 创建axios实例
const service = axios.create({// axios中请求配置有baseURL选项,表示请求URL公共部分baseURL: import.meta.env.VITE_APP_BASE_API,// 超时timeout: 100000,
})// request拦截器
service.interceptors.request.use(config => {// 省略其他配置....// 添加可取消请求配置config.cancelToken = new axios.CancelToken(c => setToken(c))return config
}, error => {console.log(error)Promise.reject(error)
})// 响应拦截器
service.interceptors.response.use(res => {// 未设置状态码则默认成功状态const code = res.data.code || '0'// 获取错误信息const msg = errorCode[code] || res.data.message || errorCode['default']// 二进制数据则直接返回if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {return res.data}if (code === 401 || code === '10006') {if (!isRelogin.show) {isRelogin.show = trueElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {confirmButtonText: '重新登录',cancelButtonText: '取消',type: 'warning',}).then(() => {isRelogin.show = falseuseUserStore().logOut().then(() => {location.href = '/index'})}).catch(() => {isRelogin.show = false})}return Promise.reject('无效的会话,或者会话已过期,请重新登录。')} else if (code === 500) {ElMessage({ message: msg, type: 'error' })return Promise.reject(new Error(msg))} else if (code !== '0') {ElMessage({ message: msg, type: 'error' })return Promise.reject('error')} else {return Promise.resolve(res.data)}},error => {if (error.name === 'CanceledError') {console.log('请求已取消')return Promise.reject('请求已取消')}ElMessage({ message: message, type: 'error', duration: 5 * 1000 })return Promise.reject(error)},
)
编写测试页面
<template><div><el-button type='primary' @click='send'>发起请求</el-button><el-button type='warning' @click='cancelSend'>取消最近一次请求</el-button><el-button type='warning' @click='cancelAllSend'>取消所有请求</el-button></div>
</template><script setup>
import { testAxiosServer } from '@/api/testApi.js'
import { cancelToken, clearAllToken } from '@/utils/globalCancelToken.js'function send() {testAxiosServer().then(res => {console.log(res)})
}function cancelSend() {cancelToken()
}function cancelAllSend() {clearAllToken()
}// 组件销毁前取消所有未完成的请求
onUnmounted(() => {clearAllToken()
})
</script>