前提准备
首先编写一个测试接口,模拟接口延迟返回,请求5秒后再返回结果
使用 node + koa
来实现
1 2 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 属性传递它。
1 2 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 属性传递它。
1 2 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
1 2 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
在请求拦截器中添加取消请求的配置,相应拦截器中判断错误类型是否为取消请求
1 2 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) }, )
|
编写测试页面
1 2 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>
|
