前端:防止重复请求的方案

前端:防止重复请求的方案

  • 方案一、axios请求拦截器
  • 方案二、把相同的请求拦截掉
  • 方案三、(最佳推荐)

方案一、axios请求拦截器

通过使用 axios拦截器,在请求拦截器中开启全屏Loading,然后再响应拦截器中关闭。

import axios from "axios";
import { ElLoading } from "element-plus"let instance = axios.create({baseURL = "/api/"
})
let loadingInstance = null;
instance.interceptors.request.use((config)=>{loadingInstance = ElLoading.service({fullscreen:true,background:"rgba(0,0,0,0.7)"});return config;
},(error)=>{return Promise.reject(error);
})
instance.interceptors.response.use((response)=>{loadingInstance = close(0);return response;
},(error)=>{return Promise.reject(error);
})
export default instance;

缺点:全屏Loading不适合所有请求,不美观

方案二、把相同的请求拦截掉

1.判断什么样的请求属于相同的请求?
请求方法、地址、参数、页面hash,可以根据这几个数据来生成一个key作为请求的标识

// 根据请求生成对应的key
function generateReqKey (config,hash){const {method,url,params,data}=config;return [method,url,JSON.stringify(params),JSON.stringify(data),hash].join("&")
}
// 存储已发送但是没有响应的请求
const pendingRequest=new Set();// 添加请求拦截器
instance.interceptors.request.use((config)=>{let hash = location.hash;// 生成请求keylet reqKey = generateReqKey (config,hash);if(pendingRequest.has(reqKey )){return Promise.reject();} else {// 将请求的key保存在configconfig.pendKey = reqKey;pendingRequest.add(reqKey);}return config;
},(error)=>{return Promise.reject(error);
})
// 添加响应拦截器
instance.interceptors.response.use((response)=>{// 从config中取出请求key,并从集合中删除pendingRequest.delete(response.config.pendKey);return response;
},(error)=>{pendingRequest.delete(error.config.pendKey);return Promise.reject(error);
})
export default instance;

2、缺点:会导致多次报error消息提示,很不友好;如果在error中有更多的逻辑处理,会导致整个程序的异常;若两个请求来自同一个页面(一个页面里面的两个组件都需要调用同一个接口时),后调的接口的组件无法拿到正确的数据。

方案三、(最佳推荐)

延续方案二的思路,对于相同的请求我们先给它挂起,等到最先发出的请求拿回结果后,把成功或失败的结果共享到后面到来的相同的请求。
1、挂起请求时,要用到发布订阅模式
2、对于挂起的请求,一定要在请求拦截器中通过return Promise.reject()来直接中断请求,并做一些特殊标记,以便于在响应拦截器中进行特殊处理

import axios from "axios";let instance = axios.create({baseURL = "/api/"
})
// 发布订阅
class EventeEmitter {constructor(){this.event={};}on(type,cbres,cbrej){if(!this.event[type]){this.event[type]=[[cbres,cbrej]];}else{this.event.push([cbres,cbrej]);}}emit(type,res,ansType){if(!this.event[type])return;else{this.event[type].forEach(cbArr=>{if(ansType==="resolve"){cbArr[0](res);}else{cbArr[1](res);}})}}
}
// 根据请求生成对应的key
function generateReqKey (config,hash){const {method,url,params,data}=config;return [method,url,JSON.stringify(params),JSON.stringify(data),hash].join("&")
}
// 存储已发送但是没有响应的请求
const pendingRequest=new Set();
// 发布订阅容器
const ev = new EventEmitter();// 添加请求拦截器
instance.interceptors.request.use(async(config)=>{if(isFileUploadApi(config) ) return;let hash = location.hash;// 生成请求keylet reqKey = generateReqKey (config,hash);if(pendingRequest.has(reqKey )){// 如果请求相同,在这里将请求挂起,通过发布订阅来为该请求返回// 在这里注意,拿到结果后,无论成功与否,都需要return Promise(),
// 则请求会正常发送到服务器。let res = null;try {// 接口成功响应res = await new Promise((resolve,reject)=>{ev.on(reqKey,resolve,reject);})return Promise.reject({type:"limiteResSuccess";val:res});}catch(limitFunErr){return Promise.reject({type:"limiteResError";val:limitFunErr});}} else {// 将请求的key保存在configconfig.pendKey = reqKey;pendingRequest.add(reqKey);}return config;
},(error)=>{return Promise.reject(error);
})
// 添加响应拦截器
instance.interceptors.response.use((response)=>{//将拿到的结果发布给其他相同的接口handleSuccessResponse_limit(response);return response;
},(error)=>{return handleErrorResponse_limit(error);
})
// 接口响应成功
function handleSuccessResponse_limit(response){const reqKey = response.config.pendKey;if(pendingRequest.has(reqKey )){let x=null;try{x=JSON.parse(JSON.stringify(response));}catch(e){x=response;}pendingRequest.delete(reqKey);ev.emit(reqKey,x,"resolve");delete ev.reqKey;}
}
// 接口响失败
function handleErrorResponse_limit(error){if(error.type && error.type === "limitResSuccess"){return Promise.resolve(error.val)}else if(error.type && error.type === "limitResError"){return Promise.rejct(error.val)}else{const reqKey = error.config.pendKey;if(pendingRequest.has(reqKey )){let x=null;try{x=JSON.parse(JSON.stringify(error));}catch(e){x=response;}pendingRequest.delete(reqKey);ev.emit(reqKey,x,"resolve");delete ev.reqKey;}}return Promise.reject(error);
}
// 判断是否是文件类型
function isFileUploadApi(config){return Object.prototype.toString.call(config.data)==="[object FormData]";
}
export default instance;

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

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

相关文章

@JsonValue的用法

jackson学习-JSON相关注解 在实际开发过程中对于对象转json有很多的工具类,这里使用的是jackson springboot 中jackson的用法 1 springboot工程本身就集成了jackson 只要是引入 org.springframework.boot spring-boot-starter-web 这个pom的可以直接使用 springbo…

【C#】rdlc报表答应报错:未能加载文件或程序集“Microsoft.SqlServer.Types

文章目录 一、报错信息二、解决方式 一、报错信息 Microsoft.Reporting.WinForms.LocalProcessingException: An error occurred during local report processing. —> Microsoft.Reporting.DefinitionInvalidException: The definition of the report ‘’ is invalid. —&…

Vmware 虚拟机自定义IP地址 - UbuntuServer2204

Vmware 虚拟机自定义IP地址 - UbuntuServer2204 设置网段 选择喜欢的网段, 例如: 166 自定义 IP地址 打开虚拟机, 输入命令查看网卡名 ip addr查看网卡配置文件 ls -al /etc/netplan/编辑网卡配置文件 sudo vim /etc/netplan/00-installe…

C++ //练习 12.20 编写程序,逐行读入一个输入文件,将内容存入一个StrBlob中,用一个StrBlobPtr打印出StrBlob中的每个元素。

C Primer(第5版) 练习 12.20 练习 12.20 编写程序,逐行读入一个输入文件,将内容存入一个StrBlob中,用一个StrBlobPtr打印出StrBlob中的每个元素。 环境:Linux Ubuntu(云服务器) 工…

实习学习内容-WS协议

WS协议,即WebSocket协议,是一种网络通信协议,提供了一种在单个长连接上进行全双工、双向交互的通信渠道。WebSocket 是独立的、创建在 TCP 上的协议。它使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送…

《从零开始的Java世界》07常用类与基础API

《从零开始的Java世界》系列主要讲解Javase部分,从最简单的程序设计到面向对象编程,再到异常处理、常用API的使用,最后到注解、反射,涵盖Java基础所需的所有知识点。学习者应该从学会如何使用,到知道其实现原理全方位式…

电脑显示有音量但是没有声音?5个方法足够解决问题!

“为什么我的电脑明明打开了声音,但是我看视频时却没有任何声音呢?应该怎么解决呀?” 在日常使用电脑的过程中,电脑声音的正常播放是很重要的,我们无论是听音乐还是看电影,都是离不开电脑声音的。遇到电脑显…

【Java EE】文件内容的读写——数据流

目录 1.InputStream概述 1.1方法 2.FileInputStream概述 2.1构造方法 2.2代码示例 2.3.利用Scanner进行字符读取 3.OutputStream概述 3.1方法 3.2利用OutputStreamWriter进行字符写入 3.3利用PrintWriter找到我们熟悉的方法 1.InputStream概述 1.1方法 修饰符及返回…

iOS 在OC旧项目中使用Swift进行混编

iOS 在OC旧项目中使用Swift进行混编 1、创建桥接文件 ​ 第一次在Swift创建OC文件,或者第一次OC创建Swift时,xcode会提示桥接,Creat Bridging Header即可,这个文件用于Swift调用OC文件,与OC调用Swift无关。 2、在TARGETS中设置D…

Linux文件系统 软硬链接

文章目录 文件背景知识磁盘文件磁盘物理结构磁盘存储结构对磁盘的存储进行逻辑抽象Boot BlockSuper blockData blocksInode TableBlcokBitmapinode BitmapGroup Descriptor Table 文件名和inode编号创建文件删除文件查找文件 软硬链接软链接硬链接查看文件信息stat命令取消软硬…

玩转智能:深度强化学习在游戏AI中的应用

玩转智能:深度强化学习在游戏AI中的应用 1 引言 1.1 简述深度强化学习(DRL)在游戏AI中的革命性影响。 当我们回顾人工智能的发展历程,可以明显地看到深度强化学习(Deep Reinforcement Learning, DRL)的出现,在游戏AI…

Docker容器的原理及应用详解(二)

本系列文章简介: Docker是一种开源的容器化技术,它将应用程序及其依赖项打包为一个容器,以便在任何环境下运行。与传统的虚拟机相比,Docker容器更加轻量级且快速,可以在几秒钟内启动和停止。Docker的原理和应用非常广泛,可以用于开发、测试、部署和扩展应用程序。 在传统…

【埋点探针】微信小程序SDK安装

一、下载微信小程序SDK埋点代码 选择Wechat,复制sdk代码 在项目根目录下,创建sdk文件,webfunny.event.js 二、在app.js文件中,引入埋点SDK代码 首先引入sdk代码 require("./webfunny.event.js")引入兼容代码&#x…

python网页篇

爬取网页动态数据通常涉及到JavaScript渲染的内容,这类数据并不是在原始HTML文档中直接提供的,而是通过AJAX请求、WebSocket通信或者其他客户端渲染技术生成的。以下是几种常见的处理方法: 方法1:使用带有JavaScript渲染功能的库 …

DHT11实验

文章目录 11.11.2 234 DS18B20 只能检测温度 右边这几个 都能 1 1.1 数字信号输出 指 0/1使用单总线通信 1个IO口就能获取温湿度 T/H要有 模数转化(内部还有个8位单片机)电容感湿元件 白色的 还有个ic NTC测温 可能在ic内部 使用单片机内部测温 精确度不…

STM32存储左右互搏 SDIO总线FATS文件读写SD/MicroSD/TF卡

STM32存储左右互搏 SDIO总线FATS文件读写SD/MicroSD/TF卡 SD/MicroSD/TF卡是基于FLASH的一种常见非易失存储单元,由接口协议电路和FLASH构成。市面上由不同尺寸和不同容量的卡,手机领域用的TF卡实际就是MicroSD卡,尺寸比SD卡小,而…

基于STM32温控风扇冷却系统设计

摘要: 在当前社会,随着大家对生活质量的追求和环保意识的加强,温控风扇作为一种节能产品备受社会的关注。温控风扇广泛应用于工业生产、家用电器、医疗美容设备和公共场所,提高了人们的生活效率和生活上的便利。这篇文章是根据单…

【网络协议】 TCP与UDP协议区别及应用场景深度分析

1. TCP与UDP简介 1.1 TCP 1.1 定义 TCP(TransmissionControl Protocol)传输控制协议。 是一种可靠的、面向连接的协议(eg:打电话)、传输效率低全双工通信(发送缓存&接收缓存)、面向字节流。使用TCP的应…

电子印章盖骑缝章

电子印章盖骑缝章是指在电子文档(如PDF文件)中,使用电子印章技术,为文档添加一个跨越多页、连续显示的电子印章图像,以模拟传统纸质文档上的骑缝章效果。以下是实现电子印章盖骑缝章的步骤: 一. 准备电子印…

docker的安装以及docker中nginx配置

机器 test3 192.168.23.103 1机器初始化配置 1.1关闭防火墙,清空防火墙规则 systemctl stop firewalld iptables -F setenforce 01.2部署时间同步 yum install ntp ntpdate -y1.3安装基础软件包 yum install -y wget net-tools nfs-utils lrzsz gcc gcc-c make…