Axios 请求取消:从原理到实践

Axios 请求取消:从原理到实践

在现代前端开发中,网络请求是不可或缺的一部分。Axios 是一个基于 Promise 的 HTTP 客户端,广泛应用于浏览器和 Node.js 环境中。然而,在某些场景下,我们可能需要取消正在进行的请求,例如用户在请求完成前跳转到其他页面,或者重复触发相同的请求时取消之前的请求。本文将深入探讨 Axios 请求取消的原理,并通过一个二次封装的例子来演示如何实现请求取消。

1. 请求取消的原理

Axios 的请求取消功能依赖于 CancelTokenCancelToken 是一个用于取消请求的令牌,它可以通过 CancelToken.source() 方法创建。每个 CancelToken 实例都有一个 token 和一个 cancel 方法。当调用 cancel 方法时,与该 token 关联的请求将被取消。

1.1 CancelToken 的工作原理

  1. 创建 CancelToken: 通过 CancelToken.source() 方法创建一个 CancelToken 实例,该实例包含一个 token 和一个 cancel 方法。
  2. 关联请求: 在发起请求时,将 token 传递给 Axios 请求配置中的 cancelToken 字段。
  3. 取消请求: 当需要取消请求时,调用 cancel 方法,Axios 会中断与该 token 关联的请求。

1.2 取消请求的流程

  1. 用户触发某个操作,发起一个请求。
  2. 在请求完成之前,用户触发了另一个操作,需要取消之前的请求。
  3. 调用 cancel 方法,Axios 中断之前的请求。
  4. 发起新的请求。

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);});},
};
  • 功能:
    • 封装了 getpostputdelete 方法,每个方法都会为请求创建一个 CancelToken,并将其存储到 cancelTokenMap 中。
    • 提供了 cancelRequestcancelAllRequests 方法,用于取消指定请求或所有请求。
  • 作用: 简化请求调用,并提供灵活的请求取消功能。

2. 请求取消的实现原理

2.1 CancelToken 的作用

  • CancelToken.source(): 创建一个 CancelTokenSource 对象,包含 tokencancel 方法。
  • token: 用于关联请求。
  • cancel: 用于取消请求。

2.2 请求取消的流程

  1. 发起请求时,创建一个 CancelTokenSource,并将其存储到 cancelTokenMap 中。
  2. 如果需要取消请求,调用 cancelRequestcancelAllRequests 方法。
  3. 调用 cancel 方法后,Axios 会中断与该 token 关联的请求,并抛出一个 Cancel 错误。
  4. 在响应拦截器中,清理已完成的请求记录。

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 的请求取消功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/72355.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot对接twilio发送邮件信息

要在Spring Boot应用程序中对接Twilio发送邮件信息&#xff0c;您可以使用Twilio的SendGrid API。以下是一个简单的步骤指南&#xff0c;帮助您完成这一过程&#xff1a; 1. 创建Twilio账户并获取API密钥 注册一个Twilio账户&#xff08;如果您还没有的话&#xff09;。在Twi…

【最后203篇系列】015 几种消息队列的思考

背景 队列还是非常重要的中间件&#xff0c;可以帮助我们&#xff1a;提高处理效率、完成更复杂的处理流程 最初&#xff0c;我觉得只要掌握一种消息队列就够了&#xff0c;现在想想挺好笑的。 过去的探索 因为我用python&#xff0c;而rabbitmq比较贴合快速和复杂的数据处…

TensorFlow 与 TensorFlow Lite:核心解析与层应用

1. 引言 TensorFlow 是 Google 开发的开源机器学习框架&#xff0c;支持从数据预处理、模型训练到推理部署的完整生命周期。然而&#xff0c;在嵌入式和移动设备上&#xff0c;原生 TensorFlow 过于庞大&#xff0c;因此 Google 推出了轻量级版本——TensorFlow Lite&#xff…

DeepSeek大模型在政务服务领域的应用

DeepSeek大模型作为国产人工智能技术的代表&#xff0c;近年来在政务服务领域的应用呈现多点开花的态势。通过多地实践&#xff0c;该技术不仅显著提升了政务服务的效率与智能化水平&#xff0c;还推动了政府治理模式的创新。以下从技术应用场景、典型案例及发展趋势三个维度进…

电子电气架构 --- 分布到集中的动カ系统及基于域控制器的架构

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所有人的看法和评价都是暂时的,只有自己的经历是伴随一生的,几乎所有的担忧和畏惧,都是来源于自己的想象,只有你真的去做了,才会发现有多快乐。…

深入理解C/C++堆数据结构:从原理到实战

一、堆的本质与特性 1.1 什么是堆数据结构&#xff1f; 堆&#xff08;Heap&#xff09;是一种特殊的完全二叉树&#xff0c;它满足以下核心性质&#xff1a; 堆序性&#xff1a;每个节点的值都满足特定顺序关系 结构性&#xff1a;完全二叉树的结构特性&#xff08;除最后一…

Python学习第十七天

Django框架-SQLite3 介绍 Django内置了对 SQLite3 数据库的支持。SQLite3 是一个轻量级的嵌入式数据库引擎&#xff0c;非常适合开发、测试和小型项目。以下是关于 Django 中 SQLite3 的介绍和应用指南。&#xff08;除了这些还支持mysql、oracle以及其他查询文档&#xff0c;…

Docker 》》Docker Compose 》》network 网络 compose

docker 默认的网络 三种模式 # 列出所有当前主机上或Swarm集群上的网络 docker network ls#查看网络详情 docker network inspect network名称# 清除未使用的docker网络 docker network prune -f# 创建网络 ocker network create -d bridge 网络名称 docker network create –s…

Python数字信号处理之最佳等波纹滤波器阶数估计原理

Matlab中的阶数估计函数 在MATLAB中&#xff0c;使用firpmord函数可以估算等波纹FIR滤波器的最小阶数。该方法基于Parks-McClellan算法&#xff0c;通过通带和阻带的频率边界、幅度响应及允许的最大误差来自动计算参数。 rp 3; % Passband ripple in dB rs 40; …

JumpServer基础功能介绍演示

堡垒机可以让运维人员通过统一的平台对设备进行维护&#xff0c;集中的进行权限的管理&#xff0c;同时也会对每个操作进行记录&#xff0c;方便后期的溯源和审查&#xff0c;JumpServer是由飞致云推出的开源堡垒机&#xff0c;通过简单的安装配置即可投入使用&#xff0c;本文…

C++和C的区别

C和C语言虽然共享相似的语法&#xff0c;但在设计理念和功能特性上有显著区别。以下是两者的主要差异&#xff1a; 1. 编程范式 C&#xff1a;纯过程式编程&#xff0c;强调函数和步骤。C&#xff1a;支持多范式&#xff0c;包括面向对象编程&#xff08;类、继承、多态&…

Android LeakCanary 使用 · 原理详解

一、简介 LeakCanary 是 Square 公司开源的 Android 内存泄漏检测工具&#xff0c;通过自动化监控和堆转储分析&#xff0c;帮助开发者快速定位内存泄漏根源。其核心设计轻量高效&#xff0c;已成为 Android 开发中必备的调试工具。 二、使用方式 1. 集成步骤 在项目的 buil…

每日一题---dd爱框框(Java中输入数据过多)

dd爱框框 实例&#xff1a; 输入&#xff1a; 10 20 1 1 6 10 9 3 3 5 3 7 输出&#xff1a; 3 5 这道题要解决Java中输入的数过多时&#xff0c;时间不足的的问题。 应用这个输入模板即可解决&#xff1a; Java中输入大量数据 import java.util.*; import java.io.*;pu…

redis部署架构

一、redis多实例部署 实例1 安装目录&#xff1a;/app/6380 数据目录&#xff1a;/app/6380/data 实例2 安装目录&#xff1a;/app/6381 数据目录&#xff1a;/app/6381/data 1、创建实例安装目录 2、拷贝实例的配置文件 3、编辑实例的配置文件 第…

vscode python相对路径的问题

vscode python相对路径的问题 最近使用使用vscode连接wsl2写python时&#xff0c;经常遇到找不到包中的方法的问题&#xff0c;最终发现vscode在执行python代码时目录不是从当前python文件开始算起&#xff0c;而是从当前工作区的目录开始算起&#xff0c;比如说我打开的是/ho…

面试vue2开发时怎么加载编译速度(webpack)

可以输入命令获取默认 webpack 设置 vue inspect > set.js 1.使用缓存 configureWebpack: {cache: {type: filesystem, // 使用文件系统缓存类型buildDependencies: {config: [__filename] // 缓存依赖&#xff0c;例如webpack配置文件路径}}}, 2.启用 vue-loader (测试明…

uv命令介绍(高性能Python包管理工具,旨在替代pip、pip-tools和virtualenv等传统工具)

文章目录 **主要功能**1. **快速安装和管理 Python 包**2. **生成和管理锁文件 (requirements.lock)**3. **创建虚拟环境**4. **与 poetry 兼容** **核心优势**1. **极快的速度**&#xff1a;基于 Rust 实现&#xff0c;利用多线程和缓存大幅加速依赖解析。2. **轻量且独立**&a…

企业数据管理的成本与效率革命

在数字经济时代&#xff0c;企业每天产生的数据量正以指数级速度增长。IDC预测&#xff0c;到2025年全球数据总量将突破180 ZB。面对海量数据存储需求和有限的IT预算&#xff0c;企业逐渐意识到&#xff1a;将每字节数据都存储在昂贵的高性能存储设备上&#xff0c;既不经济也不…

深度学习-服务器训练SparseDrive过程记录

1、cuda安装 1.1 卸载安装失败的cuda 参考&#xff1a;https://blog.csdn.net/weixin_40826634/article/details/127493809 注意&#xff1a;因为/usr/local/cuda-xx.x/bin/下没有卸载脚本&#xff0c;很可能是apt安装的&#xff0c;所以通过执行下面的命令删除&#xff1a; a…

洛谷每日1题-------Day20__P1401 [入门赛 #18] 禁止在 int 乘 int 时不开 long long

题目描述 在比赛中&#xff0c;根据数据范围&#xff0c;分析清楚变量的取值范围&#xff0c;是非常重要的。int 类型变量与 int 类型变量相乘&#xff0c;往往可能超出 int 类型可以表示的取值范围。 现在&#xff0c;给出两个 int 类型变量 x,y 及其取值范围&#xff0c;请…