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 = 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

在请求拦截器中添加取消请求的配置,相应拦截器中判断错误类型是否为取消请求

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 = 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)
  },
)

编写测试页面

<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>

axios

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值