Axios 请求取消:从原理到实践
Axios 请求取消:从原理到实践
在现代前端开发中,网络请求是不可或缺的一部分。Axios 是一个基于 Promise 的 HTTP 客户端,广泛应用于浏览器和 Node.js 环境中。然而,在某些场景下,我们可能需要取消正在进行的请求,例如用户在请求完成前跳转到其他页面,或者重复触发相同的请求时取消之前的请求。本文将深入探讨 Axios 请求取消的原理,并通过一个二次封装的例子来演示如何实现请求取消。
1. 请求取消的原理
Axios 的请求取消功能依赖于 CancelToken。CancelToken 是一个用于取消请求的令牌,它可以通过 CancelToken.source() 方法创建。每个 CancelToken 实例都有一个 token 和一个 cancel 方法。当调用 cancel 方法时,与该 token 关联的请求将被取消。
1.1 CancelToken 的工作原理
- 创建 CancelToken: 通过
CancelToken.source()方法创建一个CancelToken实例,该实例包含一个token和一个cancel方法。 - 关联请求: 在发起请求时,将
token传递给 Axios 请求配置中的cancelToken字段。 - 取消请求: 当需要取消请求时,调用
cancel方法,Axios 会中断与该token关联的请求。
1.2 取消请求的流程
- 用户触发某个操作,发起一个请求。
- 在请求完成之前,用户触发了另一个操作,需要取消之前的请求。
- 调用
cancel方法,Axios 中断之前的请求。 - 发起新的请求。
2. 二次封装 Axios 实现请求取消
为了更好地管理请求取消逻辑,我们可以对 Axios 进行二次封装。以下是一个简单的封装示例,展示了如何在封装中实现请求取消功能。
1. 代码结构分析
1.1 Axios 实例的创建
const instance: AxiosInstance = axios.create({baseURL: import.meta.env.VITE_API_BASE_URL,timeout: 10000,headers: {'Content-Type': 'application/json',},
});
baseURL: 从环境变量中获取 API 的基础 URL。timeout: 设置请求超时时间为 10 秒。headers: 设置默认请求头为application/json。
通过 axios.create 创建了一个 Axios 实例 instance,后续的所有请求都将基于这个实例。
1.2 取消令牌的管理
const cancelTokenMap = new Map<string, CancelTokenSource>();
cancelTokenMap: 使用Map数据结构来存储每个请求的取消令牌。键是请求的 URL,值是对应的CancelTokenSource。- 作用: 通过 URL 快速查找和取消对应的请求。
1.3 请求拦截器
instance.interceptors.request.use((config) => {// 添加 token 到请求头const token = localStorage.getItem('token');if (token) {config.headers = config.headers || {};config.headers.Authorization = `Bearer ${token}`;}return config;},(error) => {return Promise.reject(error);}
);
- 功能: 在请求发送前,检查本地存储中是否存在
token,如果存在则将其添加到请求头中。 - 作用: 实现全局的请求头管理,例如身份验证。
1.4 响应拦截器
instance.interceptors.response.use((response: AxiosResponse) => {// 清理已完成的请求记录const url = response.config.url;if (url && cancelTokenMap.has(url)) {cancelTokenMap.delete(url);}// 处理全局响应逻辑if (response.data.code !== 0) {return Promise.reject(response.data);}return response.data;},(error) => {// 清理失败的请求记录const url = error.config?.url;if (url && cancelTokenMap.has(url)) {cancelTokenMap.delete(url);}// 处理全局错误if (error.response?.status === 401) {// 处理未授权window.location.href = '/login';}return Promise.reject(error);}
);
- 功能:
- 在请求成功时,清理
cancelTokenMap中对应的请求记录。 - 在请求失败时,清理
cancelTokenMap中对应的请求记录,并根据状态码处理全局错误(例如未授权时跳转到登录页)。
- 在请求成功时,清理
- 作用: 实现全局的响应和错误处理逻辑。
1.5 封装的请求方法
const http = {get: <T>(url: string, config?: AxiosRequestConfig): Promise<T> => {const source = axios.CancelToken.source();cancelTokenMap.set(url, source);return instance.get(url, { ...config, cancelToken: source.token });},post: <T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> => {const source = axios.CancelToken.source();cancelTokenMap.set(url, source);return instance.post(url, data, { ...config, cancelToken: source.token });},put: <T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> => {const source = axios.CancelToken.source();cancelTokenMap.set(url, source);return instance.put(url, data, { ...config, cancelToken: source.token });},delete: <T>(url: string, config?: AxiosRequestConfig): Promise<T> => {const source = axios.CancelToken.source();cancelTokenMap.set(url, source);return instance.delete(url, { ...config, cancelToken: source.token });},// 取消指定请求cancelRequest: (url: string) => {const source = cancelTokenMap.get(url);if (source) {source.cancel(`Request canceled: ${url}`);cancelTokenMap.delete(url);}},// 取消所有请求cancelAllRequests: () => {cancelTokenMap.forEach((source, url) => {source.cancel(`Request canceled: ${url}`);cancelTokenMap.delete(url);});},
};
- 功能:
- 封装了
get、post、put、delete方法,每个方法都会为请求创建一个CancelToken,并将其存储到cancelTokenMap中。 - 提供了
cancelRequest和cancelAllRequests方法,用于取消指定请求或所有请求。
- 封装了
- 作用: 简化请求调用,并提供灵活的请求取消功能。
2. 请求取消的实现原理
2.1 CancelToken 的作用
CancelToken.source(): 创建一个CancelTokenSource对象,包含token和cancel方法。token: 用于关联请求。cancel: 用于取消请求。
2.2 请求取消的流程
- 发起请求时,创建一个
CancelTokenSource,并将其存储到cancelTokenMap中。 - 如果需要取消请求,调用
cancelRequest或cancelAllRequests方法。 - 调用
cancel方法后,Axios 会中断与该token关联的请求,并抛出一个Cancel错误。 - 在响应拦截器中,清理已完成的请求记录。
3. 使用场景
3.1 取消重复请求
当用户快速点击按钮多次触发相同的请求时,可以通过 cancelRequest 方法取消之前的请求,只保留最后一次请求。
http.get('/api/data').then((data) => console.log(data)).catch((error) => {if (axios.isCancel(error)) {console.log('Request canceled:', error.message);} else {console.error('Error:', error);}});// 取消之前的请求
http.cancelRequest('/api/data');
3.2 页面跳转时取消请求
当用户跳转到其他页面时,可以通过 cancelAllRequests 方法取消所有未完成的请求,避免无效请求占用资源。
window.addEventListener('beforeunload', () => {http.cancelAllRequests();
});
完整代码
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, CancelTokenSource } from 'axios';// 创建axios实例
const instance: AxiosInstance = axios.create({baseURL: import.meta.env.VITE_API_BASE_URL,timeout: 10000,headers: {'Content-Type': 'application/json',},
});// 创建一个Map来存储取消令牌
const cancelTokenMap = new Map<string, CancelTokenSource>();// 请求拦截器
instance.interceptors.request.use((config) => {// 在这里可以添加token等全局请求头const token = localStorage.getItem('token');if (token) {config.headers = config.headers || {};config.headers.Authorization = `Bearer ${token}`;}return config;},(error) => {return Promise.reject(error);}
);// 响应拦截器
instance.interceptors.response.use((response: AxiosResponse) => {// 清理已完成的请求记录const url = response.config.url;if (url && cancelTokenMap.has(url)) {cancelTokenMap.delete(url);}// 在这里处理全局响应逻辑if (response.data.code !== 0) {return Promise.reject(response.data);}return response.data;},(error) => {// 清理失败的请求记录const url = error.config?.url;if (url && cancelTokenMap.has(url)) {cancelTokenMap.delete(url);}// 在这里处理全局错误if (error.response?.status === 401) {// 处理未授权window.location.href = '/login';}return Promise.reject(error);}
);// 封装请求方法
const http = {get: <T>(url: string, config?: AxiosRequestConfig): Promise<T> => {const source = axios.CancelToken.source();cancelTokenMap.set(url, source);return instance.get(url, { ...config, cancelToken: source.token });},post: <T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> => {const source = axios.CancelToken.source();cancelTokenMap.set(url, source);return instance.post(url, data, { ...config, cancelToken: source.token });},put: <T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> => {const source = axios.CancelToken.source();cancelTokenMap.set(url, source);return instance.put(url, data, { ...config, cancelToken: source.token });},delete: <T>(url: string, config?: AxiosRequestConfig): Promise<T> => {const source = axios.CancelToken.source();cancelTokenMap.set(url, source);return instance.delete(url, { ...config, cancelToken: source.token });},// 添加取消请求的方法// http.cancelRequest('/api/some-endpoint');cancelRequest: (url: string) => {const source = cancelTokenMap.get(url);if (source) {source.cancel(`Request canceled: ${url}`);cancelTokenMap.delete(url);}},// 取消所有请求cancelAllRequests: () => {cancelTokenMap.forEach((source, url) => {source.cancel(`Request canceled: ${url}`);cancelTokenMap.delete(url);});},
};export default http;
4. 总结
通过二次封装 Axios,我们实现了一个功能强大且易于使用的 HTTP 客户端。它不仅支持全局的请求和响应拦截,还提供了灵活的请求取消功能,适用于多种场景。希望本文能帮助你更好地理解和使用 Axios 的请求取消功能。
相关文章:
Axios 请求取消:从原理到实践
Axios 请求取消:从原理到实践 在现代前端开发中,网络请求是不可或缺的一部分。Axios 是一个基于 Promise 的 HTTP 客户端,广泛应用于浏览器和 Node.js 环境中。然而,在某些场景下,我们可能需要取消正在进行的请求&…...
【Leetcode 每日一题】3306. 元音辅音字符串计数 I
问题背景 给你一个字符串 w o r d word word 和一个 非负 整数 k k k。 返回 w o r d word word 的 子字符串 中,每个元音字母(‘a’、‘e’、‘i’、‘o’、‘u’)至少 出现一次,并且 恰好 包含 k k k 个辅音字母的子字符串…...
【A2DP】深入解读A2DP中通用访问配置文件(GAP)的互操作性要求
目录 一、模式支持要求 1.1 发现模式 1.2 连接模式 1.3 绑定模式 1.4 模式间依赖关系总结 1.5 注意事项 1.6 协议设计深层逻辑 二、安全机制(Security Aspects) 三、空闲模式操作(Idle Mode Procedures) 3.1 支持要求 …...
分享一个免费的CKA认证学习资料
关于CKA考试 CKA(Certified Kubernetes Administrator)是CNCF基金会(Cloud Native Computing Foundation)官方推出的Kubernetes管理员认证计划,用于证明持有人有履行Kubernetes管理的知识,技能等相关的能力…...
观成科技:加密C2框架Platypus流量分析
一、工具介绍 Platypus 是一款支持多会话的交互式反向 Shell 管理器。在实际的渗透测试中,为了解决 Netcat/Socat 等工具在文件传输、多会话管理方面的不足,该工具在多会话管理的基础上增加了在渗透测试中能更好发挥作用的功能(如:交互式 Sh…...
Jetson Nano NX 重装系统
本篇记录了自己刚拿到Jetson板子后,刻意去学习给板子重刷系统的过程,学会重装系统是玩嵌入式开发板的基操。 注意:我使用的是 Nvidia 官方 SDK Manager 给 Jetson 刷系统的,需要额外准备一台 linux 电脑(双系统或者虚拟…...
注解+AOP实现权限控制
注解与AOP实战:实现权限控制 在现代Java开发中,注解(Annotation)和面向切面编程(AOP)是两种强大的技术,它们能够帮助我们实现代码的解耦,提高代码的可读性和可维护性。本文将通过一…...
Java数据结构第二十三期:Map与Set的高效应用之道(二)
专栏:Java数据结构秘籍 个人主页:手握风云 目录 一、哈希表 1.1. 概念 1.2. 冲突 1.3. 避免冲突 1.4. 解决冲突 1.5. 实现 二、OJ练习 2.1. 只出现一次的数字 2.2. 随机链表的复制 2.3. 宝石与石头 一、哈希表 1.1. 概念 顺序结构以及平衡树中…...
linux系统命令——权限
一、有哪些权限 读(r)——对应数字4 写(w)——对应数字2 执行(x)——对应数字1 二、权限及数字的对应 4对应r-- 2对应-w- 1对应--x 5对应r-x 6对应rw- 7对应rwx 三、文件的基本属性 如图&#…...
设计模式-工厂模式、策略模式、代理模式、责任链模式
目录 1 工厂模式 1.1 简单工厂模式 1.2 工厂方法模式 1.3 抽象工厂模式 1.4 工厂模式适用的场合 1.5 三种工厂模式的使用选择 2 策略模式 2.1 定义 2.2 结构 3 代理模式 3.1 啥是代理模式 3.2 为啥要用代理模式 3.3 代理模式分类 3.3.1 静态代理 3.3.2 动态代理…...
nginx中间件部署
普通权限账户安装NGINX中间件 1、拥有高级权限的账户安装必要的插件 sudo yum install -y gcc-c make pcre pcre-devel zlib zlib-devel openssl openssl-devel 2、普通账户进行NGINX的脚本式安装 vi nginx_intall.sh #!/bin/bash TAR_NAME"$1" TAR_NAME_DIRba…...
PentestGPT 下载
PentestGPT 下载 PentestGPT 介绍 PentestGPT(Penetration Testing GPT)是一个基于大语言模型(LLM)的智能渗透测试助手。它结合了 ChatGPT(或其他 GPT 模型)与渗透测试工具,帮助安全研究人员自…...
JVM 2015/3/15
定义:Java Virtual Machine -java程序的运行环境(java二进制字节码的运行环境) 好处: 一次编写,到处运行 自动内存管理,垃圾回收 数组下标越界检测 多态 比较:jvm/jre/jdk 常见的JVM&…...
Java中接口隔离原则简介和代码举例
简介: 接口隔离原则(Interface Segregation Principle,ISP)是面向对象设计SOLID原则中的“I”,其核心思想是: 定义 客户端不应被迫依赖它不使用的方法。即,一个类对另一个类的依赖应建立在最…...
基于自定义线程池手写一个异步任务管理器
我们在后端执行某些耗时逻辑操作时往往会导致长时间的线程阻塞,在这种情况之下,我们往往会引一条异步线程去处理这些异步任务,如果每次都创建新的线程来处理这些任务,不仅会增加代码冗余,还可能造成线程管理混乱&#…...
sql靶场-时间盲注(第九、十关)保姆级教程
目录 时间盲注(第九、十关) 1.判断 2.确认时间盲注 2.手工尝试时间盲注 数据库名长度 数据库名字符 表数 表名长度 表名字符 字段数 字段名长度 字段名字符 4.脚本时间盲注注入 5.第十关 时间盲注(第九、十关) 1.判…...
Vuex 高级技巧与最佳实践
使用 map 辅助函数简化代码: javascript import { mapState, mapGetters } from vuexexport default {computed: {...mapState([num]),...mapGetters([doubleNum])} }模块化开发: javascript // modules/student.js export default {namespaced: true,st…...
51c自动驾驶~合集54
我自己的原文哦~ https://blog.51cto.com/whaosoft/13517811 #Chameleon 快慢双系统!清华&博世最新:无需训练即可解决复杂道路拓扑 在自动驾驶技术中,车道拓扑提取是实现无地图导航的核心任务之一。它要求系统不仅能检测出车道和交…...
大模型推理:LM Studio在Mac上部署Deepseek-R1模型
LM Studio LM Studio是一款支持离线大模型部署的推理服务框架,提供了易用的大模型部署web框架,支持Linux、Mac、Windows等平台,并提供了OpenAI兼容的SDK接口,主要使用LLama.cpp和MLX推理后端,在Mac上部署时选择MLX推理…...
扩散模型:AIGC领域的核心引擎,解锁图像生成新维度
一、扩散模型技术原理 扩散模型是一类生成模型,它运用了物理热力学中的扩散思想, 主要包括前向扩散和反向扩散两个过程。 1.1、生成模型 在深度学习中,生成模型的目标是根据给定的样本(训练数据) 生成新样本。首先给…...
Java多线程与高并发专题——原子类和 volatile、synchronized 有什么异同?
原子类和 volatile异同 首先,通过我们对原子类和的了解,原子类和volatile 都能保证多线程环境下的数据可见性。在多线程程序中,每个线程都有自己的工作内存,当多个线程访问共享变量时,可能会出现一个线程修改了共享变…...
//要求:将输入的字符串中的数字转换为罗马数字,长度小于9(运用方法:Switch方法)
import java.util.Scanner;public class Num2 {public static void main(String[] args){ // I II III IV V VI VII VIII IX//要求:将输入的字符串中的数字转换为罗马数字,长度小于9(运用方法:查表法)//1输入数字//2有效字符判断/…...
【数据结构】数据结构,算法 概念
0.本篇问题: 数据、数据元素、数据对象、数据项之间的基本关系?ADT是什么?数据结构的三要素?数据的逻辑结构有哪些?数据的存储结构有哪些?算法的五个特征?O(1) O(logn) O(n^n) O(n) O(n^2…...
pytest 框架学习总结
视频:pytest01-快速上手_哔哩哔哩_bilibili 资料:pytest 框架 - 白月黑羽 基于 Python 语言的自动化测试框架 最知名的 有如下 3 款unittest、pytest、robotframework 前两款框架主要(或者说很大程度上)是 聚焦 在 白盒单元测试…...
总结 HTTP 协议的基本格式, 相关知识以及抓包工具fiddler的使用
目录 1 HTTP是什么 2 HTTP协议格式 3 HTTP请求(Request) 3.1 认识URL 3.2 方法 3.3 认识请求"报头"(header) 4 HTTP响应详解 4.1 认识"状态码"(statuscode) 4.2 认识响应"报头"(header) 4.3 认识响应"正⽂"(body) 5 通过f…...
python中的max(),需要注意的点
words ["apple", "banana", "grape", "cherry"] 对每个单词,keylambda x: len(x) 会计算它的长度: "apple" 长度是 5"banana" 长度是 6"grape" 长度是 5"cherry" 长度…...
DeepSeek-R1大模型微调技术深度解析:架构、方法与应用全解析
1. DeepSeek-R1大模型架构设计与技术特性 1.1 架构设计 DeepSeek-R1作为超大规模语言模型,其核心架构设计包含以下创新: 专家混合架构(MoE) 采用6710亿参数的混合专家架构(MoE),每个推理过程仅激活370亿参数,实现计算效率与资源利用率的突破性提升。 Transformer框架…...
探索Maas平台与阿里 QWQ 技术:AI调参的魔法世界
摘要:本文介绍了蓝耘 Maas 平台在人工智能领域的表现及其核心优势,包括强大的模型支持、高效的资源调度和友好的操作界面。文章还探讨了蓝耘 Maas 平台与阿里 QWQ 技术的融合亮点及应用拓展实例,并提供了调参实战指南,最后对蓝耘 …...
Linux第三次练习
1、创建根目录结构中的所有的普通文件 首先在根目录下面新创建一个test目录,然后将查找到的普通文件新建到test目录下 2、列出所有账号的账号名 3、将/etc/passwd中内容按照冒号隔开的第三个字符从大到小排序后输出所有内容 4、列出/etc/passwd中的第20行-25行内容…...
软件测试知识总结
1、黑盒测试、白盒测试、灰盒测试 1.1 黑盒测试 黑盒测试又叫功能测试、数据驱动测试 或 基于需求规格说明书的功能测试。该类测试注重于测试软件的功能性需求。 采用这种测试方法,测试工程师把测试对象看作一个黑盒子,完全不考虑程序内部的逻辑结构和…...
