当前位置: 首页 > news >正文

如何防止重复提交请求?

 

下面说的防重操作,如支付功能订单提交业务、表单提交、手机验证码功能。

 

订单提交为什么需要防重呢?想像一下你在商城购物,你选中商品点击提交订单,如果这时网络延迟没有返回成功提示,你又多点了几次。每点一次都会发送提交订单请求,若是没做防重处理,会出现生成多个订单情况。同样商城系统商品添加功能,用户不小心点了多次表单提交,若防重处理没做,将会添加多个商品。

 

如何实现防止重复提次请求操作,确保Web应用或API的健壮性和用户体验呢?我们分别从前后端操作上来说一说:

 

前端防重处理

1. 禁用按钮:在用户点击提交按钮后立即禁用它,直到服务器响应完成。

禁用按钮在注册获取手机验证码场景经常用到。点击获取验证码按钮后,按钮立即变为灰色显示禁用状态,读秒结束后恢复正常。

2. 显示加载指示:提交过程中显示加载动画或提示,防止用户再次点击。

在登录界面,用户点击登录按钮,请求登录接口后,出现加载动画,防止用户重复点击。

3. 限制提交频率:使用防抖(debounce)和节流(throttle)技术来限制事件触发的频率。

在用户点击提交按钮后,使用防抖或节流的技术延迟发送请求,确保只发送一次请求。防抖和节流是一种常见的前端性能优化技术,可以控制函数的执行频率。

在搜索框输入内容时,可能需要在用户停止输入一段时间后才发送请求,以减少请求的次数。在用户调整浏览器窗口大小时,可能需要在用户停止调整后计算布局或重新渲染页面。在用户连续按键时,例如在输入密码时,可以限制按键事件的处理频率。

 

后端防重处理

1. 唯一ID机制:生成一个唯一的ID,并在客户端提交时一并发送,服务器验证ID后进行处理。

 

以订单业务为例,实现的逻辑流程如下:

  1. 当用户进入订单提交界面的时候,调用后端获取请求唯一ID,并将唯一ID值埋点在页面里面;
  2. 当用户点击提交按钮时,后端检查这个唯一ID是否用过,如果没有用过,继续后续逻辑;如果用过,就提示重复提交
  3. 最关键的一步操作,就是把这个唯一ID 存入业务表中,同时设置这个字段为唯一索引类型,从数据库层面做防止重复提交

 

 

 

防止重复提交的大体思路如上,实践代码如下!

1. 给数据库表增加唯一键约束

2 编写获取请求唯一ID的接口

3 业务提交的时候,检查唯一ID

对于下单流量不算高的系统,可以采用这种请求唯一ID+数据表增加唯一索引约束的方式,来防止接口重复提交!虽然简单粗暴,但是十分有效!

2. 分布式锁+全局唯一的ID=Redis+Token: 分布式锁实现解决JVM锁实现单机锁局限问题

具体流程步骤:

  1. 客户端先请求服务端,会拿到一个能代表这次请求业务的唯一字段
     
  2. 将该字段以 SETNX 的方式存入 redis 中,并根据业务设置相应的超时时间
        
  3.  如果设置成功,证明这是第一次请求,则执行后续的业务逻辑
      
  4. 如果设置失败,则代表已经执行过当前请求,直接返回

Token实现:生成唯一ID

3. 幂等性设计:

幂等设计,即多次执行同一操作的结果与执行一次相同。这通常通过在接口设计时考虑实现。

总结

防止重复提交是确保Web应用或API的健壮性和用户体验的重要措施。为了防止绕过前端限制通过工具重复请求接口,在防重处理时需要前后端配合。

除了我们介绍的几种方式外还有其它方式和封装好的工具,如:react中可以用swr、ahook,vue中用VueRequest。每种方法都有其适用场景,通常需要根据具体的业务需求和系统架构来选择最合适的策略。在设计系统时,应该综合考虑多种方法,以实现最佳的效果。

 

 

 

 

相关文章:

  • 【Postman接口测试】第二节.Postman界面功能介绍(上)
  • leetcode热题100.完全平方数(动态规划进阶)
  • 如何找到docker的run(启动命令)
  • 什么是以太坊?
  • 多线程-线程池
  • Spring Boot中如何查询PGSQL分表后的数据
  • Pytorch 笔记
  • Linux入门攻坚——23、DNS和BIND基础入门2
  • 微信小程序开发(持续更新)
  • 实时合成 1 秒频订单簿快照:DolphinDB INSIGHT 行情插件与订单簿引擎应用
  • FaceChain-FACT:开源10秒写真生成,复用海量LoRa风格,基模友好型写真应用
  • 【链表】Leetcode 82. 删除排序链表中的重复元素 II【中等】
  • JavaScript日期与时间处理的艺术
  • webshell工具-冰蝎流量特征和加密方式
  • VUE3学习第一篇:启动ruoyi
  • [PHP内核探索]PHP中的哈希表
  • @jsonView过滤属性
  • canvas 五子棋游戏
  • ES6系列(二)变量的解构赋值
  • iOS动画编程-View动画[ 1 ] 基础View动画
  • Java知识点总结(JDBC-连接步骤及CRUD)
  • Linux快速配置 VIM 实现语法高亮 补全 缩进等功能
  • windows下如何用phpstorm同步测试服务器
  • Zepto.js源码学习之二
  • 初识 beanstalkd
  • 服务器从安装到部署全过程(二)
  • 如何借助 NoSQL 提高 JPA 应用性能
  • 使用 Xcode 的 Target 区分开发和生产环境
  • 算法---两个栈实现一个队列
  • 在weex里面使用chart图表
  • ionic入门之数据绑定显示-1
  • raise 与 raise ... from 的区别
  • 基于django的视频点播网站开发-step3-注册登录功能 ...
  • ​html.parser --- 简单的 HTML 和 XHTML 解析器​
  • #define与typedef区别
  • $HTTP_POST_VARS['']和$_POST['']的区别
  • (javaweb)Http协议
  • (NSDate) 时间 (time )比较
  • (翻译)terry crowley: 写给程序员
  • (附源码)计算机毕业设计ssm-Java网名推荐系统
  • (生成器)yield与(迭代器)generator
  • (四)c52学习之旅-流水LED灯
  • (四)模仿学习-完成后台管理页面查询
  • (学习日记)2024.04.04:UCOSIII第三十二节:计数信号量实验
  • (一) springboot详细介绍
  • (转)大型网站的系统架构
  • (转载)在C#用WM_COPYDATA消息来实现两个进程之间传递数据
  • **登录+JWT+异常处理+拦截器+ThreadLocal-开发思想与代码实现**
  • .class文件转换.java_从一个class文件深入理解Java字节码结构
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选
  • .NET 4.0中使用内存映射文件实现进程通讯
  • .NET Core 实现 Redis 批量查询指定格式的Key
  • .NET Standard 支持的 .NET Framework 和 .NET Core
  • .net 生成二级域名
  • .net的socket示例