前提准备
首先编写一个测试接口,模拟接口延迟返回,请求5秒后再返回结果
使用 node + koa 来实现
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | const Router = require("koa-router");const router = new Router();
 
 router.get("/getLongData", async (ctx, res) => {
 
 
 
 await new Promise((resolve) => {
 setTimeout(() => {
 resolve();
 }, 5000);
 });
 
 ctx.body = {
 code: 200,
 message: "请求成功!",
 };
 });
 
 module.exports = router;
 
 | 
AbortController
使用 AbortController
AbortController 是一个浏览器提供的 API,用于取消正在进行的异步操作,如 Fetch 请求或 Axios 请求。你可以创建一个 AbortController  实例,并在 Axios 请求配置中通过 signal 属性传递它。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | 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 属性传递它。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | 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
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 
 | let cancel = null
 
 
 let cancelTokenList = []
 
 function setToken(cancelToken) {
 cancel = cancelToken
 cancelTokenList.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
在请求拦截器中添加取消请求的配置,相应拦截器中判断错误类型是否为取消请求
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 
 | import { setToken } from '@/utils/globalCancelToken.js'
 
 const service = axios.create({
 
 baseURL: import.meta.env.VITE_APP_BASE_API,
 
 timeout: 100000,
 })
 
 
 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 = true
 ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
 confirmButtonText: '重新登录',
 cancelButtonText: '取消',
 type: 'warning',
 }).then(() => {
 isRelogin.show = false
 useUserStore().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)
 },
 )
 
 | 
编写测试页面
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 
 | <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>
 
 | 
