什么是接口幂等性?为什么会产生这个问题?如何保证接口幂等性?
off999 2025-03-20 17:39 34 浏览 0 评论
之前负责的项目报了一个问题,用户操作回退失效。我们的设计里,操作回退是回到操作前的状态。经过查看日志发现,用户之前的操作做了两次,也就是说提交操作的接口被调用了两次,导致之用户上一次的状态和这一次的状态是一样的,所以操作回退是没有问题的,问题出在了操作的接口被调用了两次。
对于防止重复提交,是放在前端控制的,用户点击完按钮之后,后台返回成功的结果,按钮就不可见,实践证明,客户端的限制操作不是绝对可靠的。
针对上面的场景,就引入了今天的问题,什么是接口幂等性?如何保证接口幂等性?
什么是接口幂等性?
首先看看幂等性的概念:
幂等性原本是数学上的概念,用在接口上就可以理解为:同一个接口,多次发出同一个请求,必须保证操作只执行一次。 调用接口发生异常并且重复尝试时,总是会造成系统所无法承受的损失,所以必须阻止这种现象的发生。
比如下面这些情况,如果没有实现接口幂等性会有很严重的后果: 支付接口,重复支付会导致多次扣钱 ;订单接口,同一个订单可能会多次创建。
为什么会产生接口幂等性问题?
那么,什么情况下,会产生接口幂等性的问题呢?
- 网络波动, 可能会引起重复请求
- 用户重复操作,用户在操作时候可能会无意触发多次下单交易,甚至没有响应而有意触发多次交易应用
- 使用了失效或超时重试机制(Nginx重试、RPC重试或业务层重试等)
- 页面重复刷新
- 使用浏览器后退按钮重复之前的操作,导致重复提交表单
- 使用浏览器历史记录重复提交表单
- 浏览器重复的HTTP请求
- 定时任务重复执行
- 用户双击提交按钮
如何保证接口幂等性?
那么最关键的来了,如何保证接口幂等性?
解决办法分为两个方向,一个方向是客户端防止重复调用,一个是服务端进行校验。当然,客户端防止重复提交并不是绝对可靠的,优点是实现起来比较简单。
- 按钮只可操作一次
一般是提交后把按钮置灰或loding状态,消除用户因为重复点击而产生的重复记录,比如添加操作,由于点击两次而产生两条记录
- token机制
功能上允许重复提交,但要保证重复提交不产生副作用,比如点击n次只产生一条记录,具体实现就是进入页面时申请一个token,然后后面所有的请求都带上这个token,后端根据token来避免重复请求。
- 使用Post/Redirect/Get模式
在提交后执行页面重定向,这就是所谓的Post-Redirect—Get(PRG)模式,简单来说就是当用户提交连表单后,跳转到一个重定向的信息页面,这样就避免用户按F5刷新导致的重复提交,而且也不会出现浏览器表单重复提交的警告,也能消除按浏览器前进和后退导致同样重复提交的问题。
- 在session存放特殊标志
在服务端,生成一个唯一的标识符,将它存入session,同时前端获取这个标识符的值将它写入表单的隐藏中,用于用户输入信息后点击一起提交,在服务器端,获取表单中隐藏字段的值,与session中的唯一标识符比较,相等说明是首次提交,就处理本次请求,然后将session中的唯一标识符移除,不相等则表示是重复提交,不再做处理。
- 使用唯一索引防止新增脏数据
利用数据库唯一索引机制,当数据重复时,插入数据库会抛出异常,保证不会出现脏数据。
- 乐观锁
如果更新已有数据,可以进行加锁更新,也可以设计表结构时使用乐观锁,通过version来做乐观锁,这样既能保证执行效率,又能保证幂等, 乐观锁的version版本在更新业务数据要自增
update table set version = version + 1 where id = #{id} and version = #{version}
示例: 当有重复请求的时候,第一个请求会获取当前商品的version版本号,得到的version为1,紧接着由于第一个请求还没更新商品的version,第二个请求获取的version依然也是1, 这时候第一个请求操作更新的时候带上version并作为条件并且自增更新,这时候商品的version就会变成2,当第二个请求去操作更新的时候明显version不一致导致更新失败。
- select + insert or update or delete
该方案就是操作之前先查询一下,符合要求再插入,该方案在没有并发的系统中可以解决幂等问题,在单JVM有并发的时候可以用JVM加锁来保证幂等性,在分布式环境它是无法保证幂等性,可以使用分布式来保证。
- 分布式锁
如果是分布是系统,构建全局唯一索引比较困难,例如唯一性的字段没法确定,这时候可以引入分布式锁,通过第三方的系统(redis或zookeeper),在业务系统插入数据或者更新数据,获取分布式锁,然后做操作,之后释放锁,这样其实是把多线程并发的锁的思路,引入多多个系统,也就是分布式系统中得解决思路。要点:某个长流程处理过程要求不能并发执行,可以在流程执行之前根据某个标志(用户ID+后缀等)获取分布式锁,其他流程执行时获取锁就会失败,也就是同一时间该流程只能有一个能执行成功,执行完成后,释放分布式锁(分布式锁要第三方系统提供)。
- 状态机幂等
在设计单据相关的业务,或者是任务相关的业务,肯定会涉及到状态机(状态变更图),就是业务单据上面有个状态,状态在不同的情况下会发生变更,一般情况下存在有限状态机,这时候,如果状态机已经处于下一个状态,这时候来了一个上一个状态的变更,理论上是不能够变更的,这样的话,保证了有限状态机的幂等。注意:订单等单据类业务,存在很长的状态流转,一定要深刻理解状态机,对业务系统设计能力提高有很大帮助 。
- 防重表
以支付为例: 使用唯一主键去做防重表的唯一索引,比如使用订单号作为防重表的唯一索引,每一次请求都根据订单号向防重表中插入一条数据,插入成功说明可以处理后面的业务,当处理完业务逻辑之后删除防重表中的订单号数据,后续如果有重复请求,则会因为防重表唯一索引原因导致插入失败,直接返回操作失败,直到第一次请求返回结果,可以看出防重表作用就是加锁的功能。
注: 最好结合状态机幂等先判断一下
- 缓冲队列
将请求都快速地接收下来后放入缓冲队列中,后续使用异步任务处理队列中的数据,过滤掉重复的请求,该解决方案优点是同步处理改成异步处理、高吞吐量,缺点则是不能及时地返回请求结果,需要后续轮询得处理结果。
- 全局唯一号
比如通过source来源 + 唯一序列号传入给后端,后端来判断请求是否重复,在并发时只能处理一个请求,其他相同并发请求要么返回请求重复,要么等待 前面请求执行完成后再执行。
作者:三分恶
原文链接:
https://www.cnblogs.com/three-fighter/p/14054749.html
相关推荐
- 家庭无线网怎么修改密码(家庭无线网怎么修改密码没有电脑)
-
一般更改无线网络密码的方法(以家用无线路由器提供的无线网络为参考):1、打开浏览器输入路由器地址。无线路由器的设置地址一般为“192.168.0.1或192.168.1.1”。当然也有部分路由...
- 联想笔记本系统重装win10系统
-
联想笔记本win10系统重装系统可以在电脑设置中完成。 一、首先,打开联想笔记本进入win10系统,在系统桌面左下角找到“开始菜单”中的“设置”点击打开。  ...
- vivo浏览器下载(vivo浏览器下载安装2022最新版)
-
您好! 很抱歉给您带来不便!建议您尝试以下方法哦;1、进入设置--更多设置--应用程序--全部找到该浏览器并清除该程序的数据试试哦! 2、您也可以讲该软件卸载掉进入设置--更多设置--应用程序...
- mac电脑和windows区别(mac和window有什么区别)
-
1、首先从外观上说,mac笔记本大多是超薄,轻便,好看。而windows笔记本大多数来说那就较厚了。2、价钱方面,mac也更贵,低配的manbookpro也要九千以上。3、从最基本上来说,mac搭...
- 手机设置路由器上网(手机如何上网设置路由器)
-
首先,打开手机浏览器,输入路由器的IP地址和密码,进入路由器设置页面。进入后会自动进入【设置向导】,点击设置向导【下一步】。在上网页面,选择【PPPoE(ADSL虚拟拨号)】,点击下一步。点击后,在新...
- office 2016激活工具(office professional 2016 激活工具)
-
word2016激活密钥有两种类型:永久激活码和KMS期限激活密钥。其中,永久激活密钥可以使用批量授权版永久激活密钥进行激活,如所示;而KMS期限激活密钥需要使用KMS客户端密钥进行激活,如所示。另外...
- 苹果zip文件怎么安装(ios安装zip)
-
ZIP文件一般是用于存储多个文件或文件夹的压缩包,因此在安装ZIP文件时需要解压缩文件并提取出其中的内容。具体而言,您可以按照以下步骤来安装ZIP文件:1.下载ZIP文件:从互联网上下载需要安装的Z...
- 如何安装win7双系统(怎么安装win7和win10双系统)
-
1.要安装双系统,首先将第二个系统的分区设置为系统磁盘。在您的电脑上右击,选择管理选项。2.在计算机管理窗口中,选择磁盘管理,找到剩余空间较大的分区,然后右击并选择“压缩卷”。3.输入压缩空间量,其大...
- u盘可以读取但不能写入(u盘只能读取不能写入是什么意思)
-
原因可能有如下几种情况1、U盘不被电脑windows系统所驱动。解决办法:在插上U盘之后,右键点击我的电脑===>属性硬件===>设备管理器==>通用串行总线控制器的位置会有个感叹号...
- 装机系统在哪里下载比较好(装系统去哪里装比较好)
-
对于典型的PC,云下载或本地重新安装都可以正常工作。假设您有一个快速的互联网连接,没有苛刻的下载限制,并且您的PC似乎没有处于损坏状态,那么您应该在合理的时间内让您的PC恢复到新的状态。但是...
- u盘装机制作软件哪个比较好(u盘装机软件推荐)
-
windows微软官方原版系统加上微软的U盘系统制作工具。MediaCreationTool来制作成U盘系统引导盘后来安装系统最纯净安全了。微peu盘驱动好。大白菜老毛桃什么的都用过,都是可以用的,...
- windows7家庭版密钥激活码(win7家庭版激活密钥最新)
-
首先,在桌面上右键点击“计算机”,然后选择“属性”,在窗口底部找到“激活Windows”选项,点击它。然后,选择“在线激活”,输入你的Windows7激活密钥。如果你没有激活密钥,你可以购买一个或者...
- win10好还是win7旗舰版好(windows10好还是windows7旗舰版好)
-
对于个人用户而言,我们更建议购买电脑装Windows10系统。以下是一些原因:兼容性更好:Windows10是微软最新的操作系统,支持大量的最新硬件和驱动程序,高度兼容大多数软件和设备。相比之下,...
欢迎 你 发表评论:
- 一周热门
-
-
抖音上好看的小姐姐,Python给你都下载了
-
全网最简单易懂!495页Python漫画教程,高清PDF版免费下载
-
Python 3.14 的 UUIDv6/v7/v8 上新,别再用 uuid4 () 啦!
-
python入门到脱坑 输入与输出—str()函数
-
宝塔面板如何添加免费waf防火墙?(宝塔面板开启https)
-
Python三目运算基础与进阶_python三目运算符判断三个变量
-
(新版)Python 分布式爬虫与 JS 逆向进阶实战吾爱分享
-
飞牛NAS部署TVGate Docker项目,实现内网一键转发、代理、jx
-
慕ke 前端工程师2024「完整」
-
失业程序员复习python笔记——条件与循环
-
- 最近发表
- 标签列表
-
- python计时 (73)
- python安装路径 (56)
- python类型转换 (93)
- python进度条 (67)
- python吧 (67)
- python的for循环 (65)
- python格式化字符串 (61)
- python静态方法 (57)
- python列表切片 (59)
- python面向对象编程 (60)
- python 代码加密 (65)
- python串口编程 (77)
- python封装 (57)
- python写入txt (66)
- python读取文件夹下所有文件 (59)
- python操作mysql数据库 (66)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python多态 (60)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)
