axios使用 CancelToken / AbortController 方法进行取消请求

文章目录

  • [1. CancelToken 方法使用示例](#1. CancelToken 方法使用示例)
    • [1.1 请求拦截 / 响应器写法](#1.1 请求拦截 / 响应器写法)
    • [1.2 接口定义写法](#1.2 接口定义写法)
    • [1.3 具体使用写法](#1.3 具体使用写法)
  • [2. AbortController 方法使用示例(axios~v0.22.0 及以后版本)](#2. AbortController 方法使用示例(axios~v0.22.0 及以后版本))
    • [2.1 请求拦截 / 响应器写法](#2.1 请求拦截 / 响应器写法)
    • [2.2 接口定义写法](#2.2 接口定义写法)
    • [2.3 具体使用写法](#2.3 具体使用写法)

1. CancelToken 方法使用示例

1.1 请求拦截 / 响应器写法

javascript 复制代码
// requer.js 文件
import router from '@/router'
import { ElMessage } from 'element-plus'

// 全版本兼容 CancelToken 方法 -- 示例
import axios, { CancelToken } from 'axios';
// import { getToken, setToken, getRootDomain } from './auth'

// 全局请求控制器
export const requestController = {
    pendingRequests: new Map(),

    addRequest (key, cancel) {
        this.pendingRequests.set(key, cancel);
    },

    cancelRequest (key, message = '请求已取消') {
        if (this.pendingRequests.has(key)) {
            const cancel = this.pendingRequests.get(key);
            cancel(message);
            this.pendingRequests.delete(key);
        }
    },

    removeRequest (key) {
        this.pendingRequests.delete(key);
    }
};

const service = axios.create({
    url: '/',
})

service.interceptors.request.use(config => {

        const requestKey = `${config.method}-${config.url}-${JSON.stringify(config.data || config.params)}`;

        // 取消重复请求
        requestController.cancelRequest(requestKey);

        config.cancelToken = new CancelToken((cancel) => {
            requestController.addRequest(requestKey, cancel);
        });

        return config;
    },

    (error) => {
        // if(store.loading)
        // Do something with request error
        // console.log(error); // for debug
        Promise.reject(error);
    },
);



service.interceptors.response.use(
    res => {
        const { data } = res

        const requestKey = `${res.config.method}-${res.config.url}-${JSON.stringify(res.config.data || res.config.params)}`;
        requestController.removeRequest(requestKey);

        if (data.code == 401) {
            window.sessionStorage.clear()
            router.replace('/login')
            return Promise.reject(data)
        }

        if (data.code == 500) {
            ElMessage({
                type: 'error',
                message: data?.message || '网络错误',
                center: true,
            })
            return Promise.reject(data)
        }

        return data
    },
    (error) => {
        if (axios.isCancel(error)) {
            console.log('请求被取消:', error.message);
            return new Promise(() => { });
        }
        // console.log('err' + error); // for debug
        ElMessage({
            message:
                (error && error.message) ||
                '网络错误或获取失败,请刷新后重试', // error.message,
            type: 'error',
            duration: 5 * 1000,
        });
        return Promise.reject(error);
    },
)


export default service

1.2 接口定义写法

javascript 复制代码
// api/index.js 文件
import service, { requestController } from '@/utils/requer'

// 不需要主动取消请求写法
// export const userCopyAdd = (data) => {
//   return service({
//     url: '/api/user-copy/add',
//     method: 'POST',
//     data
//   })
// }

// 需要主动取消请求写法
export const userCopyAdd = (data) => {
  const request = {
    service: () => {
      return service({
        url: '/api/user-copy/add',
        method: 'POST',
        data,
      });
    },
    cancel: () => {
      // 这里有个注意点,请求方式必须是小写,不论请求本身是怎么写的
      const key = `post-/api/user-copy/add-${JSON.stringify(data)}`;
      requestController.cancelRequest(key);
    }
  };

  return request;
}

1.3 具体使用写法

javascript 复制代码
<template>
  <!-- 取消重复请求 -- 由于接口响应速度比较快,需要将网络调整成3G网或者快速点击 -->
  <!-- 请求的接口:/user-copy/add 需启动 nest-moogodb 项目,项目地址:https://gitee.com/kuxiao-smile/node-nest -->
  <el-button size="small" @click="setUserCopyAdd">重复请求测试</el-button>
  <el-button size="small" @click="cancelUserCopyAdd">取消请求测试</el-button>
</template>
<script setup>
import { ref } from 'vue';
import { userCopyAdd } from '@/api/index'

const ruleForm = ref({})

// 添加重复请求接口拦截
const setUserCopyAdd = () => {
  // userCopyAdd(ruleForm.value)
  userCopyAdd(ruleForm.value).service().then(res => {
    ElMessage.success('添加成功')
  }).catch(error => {
    console.error('添加失败:', error); // 添加错误捕获
    ElMessage.error('添加失败: ' + (error.message || '未知错误'));
  })
}

// 取消请求
const cancelUserCopyAdd = () => {
  userCopyAdd(ruleForm.value).cancel()
}
</script>

<style lang="less" scoped></style>

2. AbortController 方法使用示例(axios~v0.22.0 及以后版本)

2.1 请求拦截 / 响应器写法

javascript 复制代码
// requer.js 文件
import router from '@/router'
import { ElMessage } from 'element-plus'

// v0.22.0 及以后版本 ( 以前版本此方法无效 ) AbortController 方法 -- 使用示例

import axios from 'axios';

export const requestController = {
  pendingRequests: new Map(),

  addRequest(key, controller) {
    this.pendingRequests.set(key, controller);
  },

  cancelRequest(key, message = '请求已取消') {
    if (this.pendingRequests.has(key)) {
      const controller = this.pendingRequests.get(key);
      controller.abort(message);
      this.pendingRequests.delete(key);
    }
  },

  removeRequest(key) {
    this.pendingRequests.delete(key);
  }
};

// 创建axios实例
const service = axios.create({
  baseURL: '/',
});

// request拦截器
service.interceptors.request.use(
  (config) => {
    const requestKey = `${config.method}-${config.url}-${JSON.stringify(config.data || config.params)}`;

    // 取消重复请求
    requestController.cancelRequest(requestKey);

    // 使用AbortController
    const controller = new AbortController();
    config.signal = controller.signal;
    requestController.addRequest(requestKey, controller);

    return config;
  },

  (error) => {
    // if(store.loading)
    // Do something with request error
    // console.log(error); // for debug
    Promise.reject(error);
  },
);

service.interceptors.response.use(
    res => {
        const { data } = res

        const requestKey = `${res.config.method}-${res.config.url}-${JSON.stringify(res.config.data || res.config.params)}`;
        requestController.removeRequest(requestKey);

        if (data.code == 401) {
            window.sessionStorage.clear()
            router.replace('/login')
            return Promise.reject(data)
        }

        if (data.code == 500) {
            ElMessage({
                type: 'error',
                message: data?.message || '网络错误',
                center: true,
            })
            return Promise.reject(data)
        }

        return data
    },
    (error) => {
        if (axios.isCancel(error)) {
            console.log('请求被取消:', error.message);
            return new Promise(() => { });
        }
        // console.log('err' + error); // for debug
        ElMessage({
            message:
                (error && error.message) ||
                '网络错误或获取失败,请刷新后重试', // error.message,
            type: 'error',
            duration: 5 * 1000,
        });
        return Promise.reject(error);
    },
)


export default service

2.2 接口定义写法

javascript 复制代码
// api/index.js 文件
import service, { requestController } from '@/utils/requer'

// 不需要主动取消请求写法
// export const userCopyAdd = (data) => {
//   return service({
//     url: '/api/user-copy/add',
//     method: 'POST',
//     data
//   })
// }

// 需要主动取消请求写法
export const userCopyAdd = (data) => {
  const request = {
    service: () => {
      return service({
        url: '/api/user-copy/add',
        method: 'POST',
        data,
      });
    },
    cancel: () => {
      // 这里有个注意点,请求方式必须是小写,不论请求本身是怎么写的
      const key = `post-/api/user-copy/add-${JSON.stringify(data)}`;
      requestController.cancelRequest(key);
    }
  };

  return request;
}

2.3 具体使用写法

javascript 复制代码
<template>
  <!-- 取消重复请求 -- 由于接口响应速度比较快,需要将网络调整成3G网或者快速点击 -->
  <!-- 请求的接口:/user-copy/add 需启动 nest-moogodb 项目,项目地址:https://gitee.com/kuxiao-smile/node-nest -->
  <el-button size="small" @click="setUserCopyAdd">重复请求测试</el-button>
  <el-button size="small" @click="cancelUserCopyAdd">取消请求测试</el-button>
</template>
<script setup>
import { ref } from 'vue';
import { userCopyAdd } from '@/api/index'

const ruleForm = ref({})

// 添加重复请求接口拦截
const setUserCopyAdd = () => {
  // userCopyAdd(ruleForm.value)
  userCopyAdd(ruleForm.value).service().then(res => {
    ElMessage.success('添加成功')
  }).catch(error => {
    console.error('添加失败:', error); // 添加错误捕获
    ElMessage.error('添加失败: ' + (error.message || '未知错误'));
  })
}

// 取消请求
const cancelUserCopyAdd = () => {
  userCopyAdd(ruleForm.value).cancel()
}
</script>

<style lang="less" scoped></style>
相关推荐
小酒星小杜3 小时前
在AI时代,技术人应该每天都要花两小时来构建一个自身的构建系统
前端·vue.js·架构
测试游记3 小时前
基于 FastGPT 的 LangChain.js + RAG 系统实现
开发语言·前端·javascript·langchain·ecmascript
阿奇__3 小时前
elementUI table 多列排序并保持状态样式显示正确(无需修改源码)
前端·vue.js·elementui
Van_captain3 小时前
rn_for_openharmony常用组件_Empty空状态
javascript·开源·harmonyos
zhengxianyi5153 小时前
数据大屏-单点登录ruoyi-vue-pro
前端·javascript·vue.js
我想回家种地3 小时前
python期末复习重点
前端·javascript·python
行者963 小时前
Flutter适配OpenHarmony:高效数据筛选组件的设计与实现
开发语言·前端·flutter·harmonyos·鸿蒙
Van_Moonlight3 小时前
RN for OpenHarmony 实战 TodoList 项目:底部 Tab 栏
javascript·开源·harmonyos
Van_Moonlight3 小时前
RN for OpenHarmony 实战 TodoList 项目:浮动添加按钮 FAB
javascript·开源·harmonyos
Serendipity-Solitude3 小时前
HTML 五子棋实现方法
前端·html