Spring Boot 如何防止重复请求?| 超级详细,建议收藏

news2024/11/23 12:09:42

1. 前言🔥

        在日常业务开发中,处理重复请求应该是我们需要经常注意的,在某些情况下是可能重复发送的,如果是查询类操作并无大碍,但其中有些请求是涉及写入操作的,一旦重复了,很可能会导致很严重的后果,例如交易的接口如果重复请求就可能会重复下单。还比如如下场景:

  1. 黑客拦截了请求,重放

  2. 前端/客户端因为某些原因重复请求了,或者用户在很短的时间内多次点击请求。

  3. 网关重发

  4. ….

        那么在Spring Boot 中,防止重复请求的方法有那些?像如何禁止用户重复点击等客户端操作将不在本文的讨论范畴(有点low),我要玩点高级的,同学们请看:

  • Token 验证

解析:在页面中生成一个唯一的Token,然后在请求中携带此Token,服务端接收到请求后验证解析该Token是否是正确的。如果Token不正确,则认为是重复请求并过滤/拒绝该次请求。

  • Token 桶算法

解析:在服务端中使用Token桶算法对请求进行限制,每个用户都有一个Token桶,每次请求需要从Token桶中获取一个Token,如果Token桶中没有用户此次请求的Token,则认为是重复请求并过滤/拒绝该次请求。

  • 限流控制

解析:通过在请求接口中设置一个时间间隔,例如5秒钟,同一个用户在5秒钟内只能请求一次,如果再次请求则认为是重复请求并过滤/拒绝该次请求。

  • 接口密等性设计

解析:通过设计接口的幂等性来防止重复请求。在设计接口时,确保同样的请求不管发送多少次都会得到相同的结果,这样即使用户发送了重复请求,服务端都返回同一种请求结果,也就不会对系统及数据造成影响。

        那么,具体如何一一实现呢?这将又会是干货满满的一期,全程无尿点不废话只抓重点教,具有非常好的学习效果,拿好小板凳准备就坐!希望学习的过程中大家认真听好好学,学习的途中有任何不清楚或疑问的地方皆可评论区留言或私信,bug菌将第一时间给予解惑,那么废话不多说,直接开整!Fighting!! 

2. 环境说明🔥

本地的开发环境:

  • 开发工具:IDEA 2021.3
  • JDK版本: JDK 1.8
  • Spring Boot版本:2.3.1 RELEASE
  • Maven版本:3.8.2

3. 正文🔥 

        那么接下来,我就给同学们逐一具体介绍下如上四种防止重复请求的解决方案吧。

3.1 Token验证

3.1.1 思路

        在页面中生成一个唯一的Token,然后在请求中携带此Token,服务端接收到请求后验证解析该Token是否是正确的。如果Token不正确,则认为是重复请求并过滤/拒绝该次请求。

3.1.2 代码示例

①首先在页面中生成一个唯一的Token

 <form id="demoForm" action="/submit" method="post">
     <input type="hidden" name="token" value="${token}" />
     <!-- 其他表单元素 -->
     <button type="submit">提交</button>
 </form>

②在服务端中接收请求并验证Token

 @RestController
 public class DemoController{
 ​
     private Map<String, Boolean> tokenMap = new ConcurrentHashMap<>();
 ​
     @PostMapping("/submit")
     public String submit(HttpServletRequest request) {
         //获取请求携带的参数token值
         String token = request.getParameter("token");
         //校验是否存有
         if (!tokenMap.containsKey(token)) {
             //不存在则放过,存在则判定同一次请求
             tokenMap.put(token, true);
             // 处理请求
             return "success";
         } else {
             // 重复请求
             return "error";
         }
     }
 }

3.2 Token桶算法

3.2.1 思路

        在服务端中使用Token桶算法对请求进行限制,每个用户都有一个Token桶,每次请求需要从Token桶中获取一个Token,如果Token桶中没有用户此次请求的Token,则认为是重复请求并过滤/拒绝该次请求。

3.2.2 代码示例

 @RestController
 public class DemoController {
 ​
     private Map<String, LinkedList<Long>> tokenBucketMap = new ConcurrentHashMap<>();
 ​
     @PostMapping("/submit")
     public String submit(HttpServletRequest request) {
         //获取用户id
         String userId = request.getParameter("userId");
         //通过用户id生成一个token桶
         LinkedList<Long> tokenBucket = tokenBucketMap.get(userId);
         if (tokenBucket == null) {
             tokenBucket = new LinkedList<>();
             tokenBucketMap.put(userId, tokenBucket);
         }
         long currentTime = System.currentTimeMillis();
         synchronized (tokenBucket) {
             if (tokenBucket.size() < 10 || currentTime - tokenBucket.getFirst() > 60000) {
                 tokenBucket.addLast(currentTime);
                 if (tokenBucket.size() > 10) {
                     tokenBucket.removeFirst();
                 }
                 // 处理请求
                 return "success";
             } else {
                 // 重复请求
                 return "error";
             }
         }
     }
 }

3.3 限流控制

3.3.1 思路

        通过在请求接口中设置一个时间间隔,例如5秒钟,同一个用户在5秒钟内只能请求一次,如果再次请求则认为是重复请求并过滤/拒绝该次请求。

3.3.2 代码示例

@RestController
 public class DemoController {
 ​
     private Map<String, Long> lastRequestTimeMap = new ConcurrentHashMap<>();
 ​
     @PostMapping("/submit")
     public String submit(HttpServletRequest request) {
         //获取请求中的用户id
         String userId = request.getParameter("userId");
         //从map中查找上次请求的时间戳
         Long lastRequestTime = lastRequestTimeMap.get(userId);
         //如果为空或者上次请求的时间戳与当前时间做差大于5s,则视为新请求,否则重复请求。
         if (lastRequestTime == null || System.currentTimeMillis() - lastRequestTime > 5000) {
             lastRequestTimeMap.put(userId, System.currentTimeMillis());
             // 处理请求
             return "success";
         } else {
             // 重复请求
             return "error";
         }
     }
 }

3.4 接口密等性设计

3.4.1 思路

        通过设计接口的幂等性来防止重复请求。在设计接口时,确保同样的请求不管发送多少次都会得到相同的结果,这样即使用户发送了重复请求,服务端都返回同一种请求结果,也就不会对系统及数据造成影响。

3.4.2 代码示例

 @RestController
 public class DemoController {
 ​
     private Map<String, String> resultCache = new ConcurrentHashMap<>();
 ​
     @PostMapping("/submit")
     public String submit(HttpServletRequest request) {
         //指定一个请求参数key。
         String key = request.getParameter("key");
         //将请求结果存放到key值里
         String result = resultCache.get(key);
         //如果result不为空则说明是重复请求。
         if (result != null) {
             // 返回之前的结果
             return result;
         } else {
             // 处理请求并缓存结果
             // 模拟一个结果赋值
             result = doBusinessLogic();
             // 将结果缓存
             resultCache.put(key, result);
             // 返回
             return result;
         }
     }
 ​
     private String doBusinessLogic() {
         // 业务逻辑处理
         return "success";
     }
 }

        好啦,以上就是4种解决重复请求的解决方式啦,同学们觉得那种更好可以在文末进行投票讨论交流哦。

4. 热文推荐🔥

滴~如下推荐【Spring Boot 进阶篇】的学习大纲,请小伙伴们注意查收。

Spring Boot进阶(01):Spring Boot 集成 Redis,实现缓存自由

Spring Boot进阶(02):使用Validation进行参数校验

Spring Boot进阶(03):如何使用MyBatis-Plus实现字段的自动填充

Spring Boot进阶(04):如何使用MyBatis-Plus快速实现自定义sql分页

Spring Boot进阶(05):Spring Boot 整合RabbitMq,实现消息队列服务

Spring Boot进阶(06):Windows10系统搭建 RabbitMq Server 服务端

Spring Boot进阶(07):集成EasyPoi,实现Excel/Word的导入导出

Spring Boot进阶(08):集成EasyPoi,实现Excel/Word携带图片导出

Spring Boot进阶(09):集成EasyPoi,实现Excel文件多sheet导入导出

Spring Boot进阶(10):集成EasyPoi,实现Excel模板导出成PDF文件

Spring Boot进阶(11):Spring Boot 如何实现纯文本转成.csv格式文件?

Spring Boot进阶(12):Spring Boot 如何获取Excel sheet页的数量?

Spring Boot进阶(13):Spring Boot 如何获取@ApiModelProperty(value = “序列号“, name = “uuid“)中的value值name值?

Spring Boot进阶(14):Spring Boot 如何手动连接库并获取指定表结构?一文教会你

Spring Boot进阶(15):根据数据库连接信息指定分页查询表结构信息

Spring Boot进阶(16):Spring Boot 如何通过Redis实现手机号验证码功能?

Spring Boot进阶(17):Spring Boot如何在swagger2中配置header请求头等参数信息

Spring Boot进阶(18):SpringBoot如何使用@Scheduled创建定时任务?

Spring Boot进阶(19):Spring Boot 整合ElasticSearch

Spring Boot进阶(20):配置Jetty容器

Spring Boot进阶(21):配置Undertow容器

Spring Boot进阶(22):Tomcat与Undertow容器性能对比分析

Spring Boot进阶(23):实现文件上传

Spring Boot进阶(24):如何快速实现多文件上传?

Spring Boot进阶(25):文件上传的单元测试怎么写?

Spring Boot进阶(26):Mybatis 中 resultType、resultMap详解及实战教学

Spring Boot进阶(27):Spring Boot 整合 kafka(环境搭建+演示)

Spring Boot进阶(28):Jar包Linux后台启动部署及滚动日志查看,日志输出至实体文件保存

Spring Boot进阶(29):如何正确使用@PathVariable,@RequestParam、@RequestBody等注解?不会我教你,结合Postman演示

Spring Boot进阶(30):@RestController和@Controller 注解使用区别,实战演示

...

5. 文末🔥

        如果想系统性的学习Spring Boot,小伙伴们直接订阅bug菌专门为大家创建的Spring Boot专栏《滚雪球学Spring Boot》从入门到精通,从无到有,从零到一!以知识点+实例+项目的学习模式由浅入深对Spring Boot框架进行学习&使用。

        如果你有一定的基础却又想精进Spring Boot,那么《Spring Boot进阶实战》将会是你的最好的选择;此栏进行知识点+实例+项目的学习方式全面深入框架剖析及各种高阶玩法,励志打造全网最全最新springboot学习专栏,投资学习自己性价比最高。

       我是bug菌,一名想走👣出大山改变命运的程序猿。接下来的路还很长,都等待着我们去突破、去挑战。来吧,小伙伴们,我们一起加油!未来皆可期,fighting!

关注公众号,获取最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板等硬核资源

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

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

相关文章

【Python】模块导入 ② ( 模块导入语法 | 导入完整模块 | import 导入完整模块 | from 导入完整模块 )

文章目录 一、导入完整模块 - import 导入完整模块1、import 导入完整模块2、代码示例 - 导入 time 时间模块 二、导入完整模块 - from 导入完整模块1、from 导入完整模块2、代码示例 - from 导入完整模块 一、导入完整模块 - import 导入完整模块 1、import 导入完整模块 使用…

Mybatis背景简介及其优缺点

文章目录 1. JDBC简介1.1 jdbc架构图1.2 jdbc例子1.3 jdbc缺点 2. Mybatis2.1 iBATIS是什么2.2 Mybatis是什么2.3 和其他持久层框架的本质区别2.4 Mybatis和Hibernate的共同点2.5 Mybatis的优缺点2.5.1 Mybatis的优点2.5.2 Mybatis的缺点 2.6 Hibernate的优缺点2.6.1 Hibernate…

工作流引擎技术选型

一、主流开源框架介绍 1、工作流相关文档 1.Camunda 官方文档&#xff1a;https://camunda.com/ 中文文档&#xff1a;介绍 | docs.camunda.org 2.Activiti 官方文档&#xff1a;https://www.activiti.org/ 中文文档&#xff1a;[activiti6用户手册 3.Snaker 官方文档&…

【PCIE体系结构十四】电气物理层之发送端FFE

&#x1f449;个人主页&#xff1a;highman110 &#x1f449;作者简介&#xff1a;一名硬件工程师&#xff0c;持续学习&#xff0c;不断记录&#xff0c;保持思考&#xff0c;输出干货内容 参考书籍&#xff1a;《PCI.EXPRESS系统体系结构标准教材 Mindshare》 参考文章&…

Docker 安装 Nginx,并实现负载均衡

1、获取 nginx 的镜像 # 默认是latest版本docker pull nginx 2、运行 nginx 容器 docker run --name nginx-80 -p 80:80 --rm -d nginx# --name nginx-80 设定容器的名称# -p 80:80 端口进行映射&#xff0c;将本地的80端口映射到容器内部的80端口# --rm 表示容器退出后直接…

云安全技术——Hyper-V虚拟化技术

目录 5-1 了解Hyper-V 5-2 安装Hyper-V 5-3创建虚拟机 Hyper-V虚拟化技术 实验目的 了解 Windows 虚拟化的概念 了解 Hyper-V的背景及发展 了解 Hyper-V 的功能特性 了解 Hyper-V的体系架构 实验要求 能描述 Hyper-V 的功能特性 能在 Windows 2012 R2系统下部署 Hyper-V 能使…

SpringBoot整合MyBatis分页

SpringBoot整合MyBatis分页 一、pagehelper分页1、添加相关依赖2、添加相关配置3、添加分页配置4、添加代码5、测试 二、拦截器分页1、添加相关配置2、添加拦截器代码和配置3、添加代码4、测试4、测试 本文目标&#xff1a; SpringBoot整合Mybatis分页的两种方式&#xff0c;一…

Python基础八

目录 一、Python条件控制语句 1.执行过程 2.if 语句 if中常用的操作运算符: if 嵌套 3.match...case语句 二、Python循环控制语句 1.while循环 while无限循环 while 循环使用 else 语句 2.for 循环语句 for...in...循环 for循环使用else语句 for...in range()…

2023年3季度DAMA-CDGA/CDGP数据治理认证即将开班

DAMA认证为数据管理专业人士提供职业目标晋升规划&#xff0c;彰显了职业发展里程碑及发展阶梯定义&#xff0c;帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力&#xff0c;促进开展工作实践应用及实际问题解决&#xff0c;形成企业所需的新数字经济下的核心职业…

你知道ai绘画生成器怎么弄吗

在数字时代&#xff0c;艺术也开始走向了自动化。随着人工智能技术的进步&#xff0c;ai绘画软件已经开始逐渐普及。它们可以利用先进的神经网络算法&#xff0c;学习人类艺术家的风格和技巧&#xff0c;从而生成出高度逼真的艺术作品。这些作品虽然没有人类艺术家的创意和灵魂…

Linux系统编程(终端和进程的关系)

文章目录 前言一、终端和控制台二、TTY和PTY三、终端的类型四、Gnome Terminal伪终端总结 前言 本篇文章带大家学习终端和进程的关系&#xff0c;终端相信大家都听过&#xff0c;那么真的理解终端是什么吗&#xff1f;应该有很多同学对于终端只是有一个模糊的概念。那么这篇文…

【算法题】合并两个有序链表、删除字符串 s1 中在字符串 s2 中出现的字符、求一个论坛一天的在线人数分布

合并两个有序链表、删除字符串 s1 中在字符串 s2 中出现的字符、求一个论坛一天的在线人数分布 一、合并两个有序链表1.1、题目描述1.2、思路1.3、代码实现1.4、小结 二、删除字符串 s1 中在字符串 s2 中出现的字符2.1、题目描述2.2、思路2.3、代码实现2.4、小结 三、求一个论坛…

项目进度类知识要点

单代号网络图 六标时法正推法逆推法 六标时法最早开始时间(ES)工期最早完成时间(EF)活动名称/活动编号最迟开始时间(LS)浮动时间(总时差)最迟完成时间(LF) 关键路径、计算项目的总工期 关键路径是最大长度关键路径上的活动是关键活动关键活动之和为总工期 关键路径变化问题…

华为18级工程师三年心血终成趣谈网络协议文档(附大牛讲解)

前言 虽然在大学的时候大家都学过网络协议 &#xff0c;但是肯定感觉网络协议的知识点非常多 &#xff0c;非常复杂。学的时候就浑浑噩噩&#xff0c;真正到了实践中更是糊里糊涂&#xff0c;一旦工作中遇到了网络问题&#xff0c;除了会简单地 ping 几下 &#xff0c;基本没有…

安装Jmeter

Jmeter是Java语言开发,所以需要java环境,所以先安装jdk 1.安装JDK(1.8版本以上) 下载&#xff1a; https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html 找到对应的版本: 点击exe文件安装,跟着向导下一步 2.安装jmeter 下载 Jmeter &#xff1a; 版…

【Java】JVM(六)

垃圾回收 分代回收理论 当前商业虚拟机的垃圾回收器&#xff0c;大多遵循“分代收集”的理论来进行设计&#xff0c;这个理论大体上是这么描述的&#xff1a; 1、绝大部分的对象都是朝生夕死。 2、熬过多次垃圾回收的对象就越难回收。 根据以上两个理论&#xff0c;朝生夕…

【Java】JVM学习(四)

对象的分配 JVM中对象的创建过程 对象的内存分配 虚拟机遇到一条new指令时&#xff0c;首先检查是否被类加载器加载&#xff0c;如果没有&#xff0c;那必须先执行相应的类加载过程。 类加载就是把class加载到JVM的运行时数据区的过程。 1&#xff09;检查加载 首先检查这…

从选题、创作、编辑、推广到优化,23个必用的内容营销工具

咱们做内容营销的&#xff0c;要懂营销懂产品&#xff0c;看得懂技术语言&#xff0c;写得了行业洞察&#xff0c;做出来的内容要有创意还要接地气&#xff0c;专业内容也不能落下&#xff0c;除了会写&#xff0c;还要会运营会设计会剪视频&#xff0c;简直就是全才嘛。 但是…

你知道游戏配音怎么制作吗?教你游戏配音教程怎么做

曾经&#xff0c;有一个叫小明的游戏迷&#xff0c;他对于游戏世界充满了热爱和想象。每当他控制着自己喜爱的角色在游戏中冒险时&#xff0c;他总是希望能够为这些角色赋予独特的声音&#xff0c;让它们真正活起来。然而&#xff0c;他却面临一个问题&#xff1a;游戏配音教程…

【CTF-Reverse中的加密算法】密码算法特征识别,变种密码算法分析

上一章中我们带领大家了解了加密算法——RC4,TEA,Base64算法的原理&#xff0c;但是加密算法远不止这些&#xff0c;需要大家自行去学习&#xff0c;在这一章中&#xff0c;我来带领大家了解密码算法特征识别&#xff0c;变种密码算法分析。 一.密码算法特征识别 1.什么是特征…