博主负责的项目报了一个问题,用户操作回退失效。我们的设计里,操作回退是回到操作前的状态。经过查看日志发现,用户之前的操作做了两次,也就是说提交操作的接口被调用了两次,导致之用户上一次的状态和这一次的状态是一样的,所以操作回退是没有问题的,问题出在了操作的接口被调用了两次。

对于防止重复提交,是放在前端控制的,用户点击完按钮之后,后台返回成功的结果,按钮就不可见,实践证明,客户端的限制操作不是绝对可靠的。

针对上面的场景,就引入了今天的问题,什么是接口幂等性?如何保证接口幂等性?

什么是接口幂等性?

首先看看幂等性的概念:

幂等性原本是数学上的概念,用在接口上就可以理解为:同一个接口,多次发出同一个请求,必须保证操作只执行一次。 调用接口发生异常并且重复尝试时,总是会造成系统所无法承受的损失,所以必须阻止这种现象的发生。

比如下面这些情况,如果没有实现接口幂等性会有很严重的后果: 支付接口,重复支付会导致多次扣钱 ;订单接口,同一个订单可能会多次创建。

为什么会产生接口幂等性问题?

那么,什么情况下,会产生接口幂等性的问题呢?

  • 网络波动, 可能会引起重复请求
  • 用户重复操作,用户在操作时候可能会无意触发多次下单交易,甚至没有响应而有意触发多次交易应用
  • 使用了失效或超时重试机制(Nginx重试、RPC重试或业务层重试等)
  • 页面重复刷新
  • 使用浏览器后退按钮重复之前的操作,导致重复提交表单
  • 使用浏览器历史记录重复提交表单
  • 浏览器重复的HTTP请求
  • 定时任务重复执行
  • 用户双击提交按钮

如何保证接口幂等性?

那么最关键的来了,如何保证接口幂等性?

解决办法分为两个方向,一个方向是客户端防止重复调用,一个是服务端进行校验。当然,客户端防止重复提交并不是绝对可靠的,优点是实现起来比较简单。

  1. 按钮只可操作一次

一般是提交后把按钮置灰或loding状态,消除用户因为重复点击而产生的重复记录,比如添加操作,由于点击两次而产生两条记录

  1. token机制

功能上允许重复提交,但要保证重复提交不产生副作用,比如点击n次只产生一条记录,具体实现就是进入页面时申请一个token,然后后面所有的请求都带上这个token,后端根据token来避免重复请求。

  1. 使用Post/Redirect/Get模式

在提交后执行页面重定向,这就是所谓的Post-Redirect—Get(PRG)模式,简单来说就是当用户提交连表单后,跳转到一个重定向的信息页面,这样就避免用户按F5刷新导致的重复提交,而且也不会出现浏览器表单重复提交的警告,也能消除按浏览器前进和后退导致同样重复提交的问题。

  1. 在session存放特殊标志

在服务端,生成一个唯一的标识符,将它存入session,同时前端获取这个标识符的值将它写入表单的隐藏中,用于用户输入信息后点击一起提交,在服务器端,获取表单中隐藏字段的值,与session中的唯一标识符比较,相等说明是首次提交,就处理本次请求,然后将session中的唯一标识符移除,不相等则表示是重复提交,不再做处理。

  1. 使用唯一索引防止新增脏数据

利用数据库唯一索引机制,当数据重复时,插入数据库会抛出异常,保证不会出现脏数据。

  1. 乐观锁

如果更新已有数据,可以进行加锁更新,也可以设计表结构时使用乐观锁,通过version来做乐观锁,这样既能保证执行效率,又能保证幂等, 乐观锁的version版本在更新业务数据要自增
update table set version = version + 1 where id = #{id} and version = #{version}
示例: 当有重复请求的时候,第一个请求会获取当前商品的version版本号,得到的version为1,紧接着由于第一个请求还没更新商品的version,第二个请求获取的version依然也是1, 这时候第一个请求操作更新的时候带上version并作为条件并且自增更新,这时候商品的version就会变成2,当第二个请求去操作更新的时候明显version不一致导致更新失败。

  1. select + insert or update or delete

该方案就是操作之前先查询一下,符合要求再插入,该方案在没有并发的系统中可以解决幂等问题,在单JVM有并发的时候可以用JVM加锁来保证幂等性,在分布式环境它是无法保证幂等性,可以使用分布式来保证。

  1. 分布式锁

如果是分布是系统,构建全局唯一索引比较困难,例如唯一性的字段没法确定,这时候可以引入分布式锁,通过第三方的系统(redis或zookeeper),在业务系统插入数据或者更新数据,获取分布式锁,然后做操作,之后释放锁,这样其实是把多线程并发的锁的思路,引入多多个系统,也就是分布式系统中得解决思路。要点:某个长流程处理过程要求不能并发执行,可以在流程执行之前根据某个标志(用户ID+后缀等)获取分布式锁,其他流程执行时获取锁就会失败,也就是同一时间该流程只能有一个能执行成功,执行完成后,释放分布式锁(分布式锁要第三方系统提供)。

  1. 状态机幂等

在设计单据相关的业务,或者是任务相关的业务,肯定会涉及到状态机(状态变更图),就是业务单据上面有个状态,状态在不同的情况下会发生变更,一般情况下存在有限状态机,这时候,如果状态机已经处于下一个状态,这时候来了一个上一个状态的变更,理论上是不能够变更的,这样的话,保证了有限状态机的幂等。注意:订单等单据类业务,存在很长的状态流转,一定要深刻理解状态机,对业务系统设计能力提高有很大帮助 。

  1. 防重表

以支付为例: 使用唯一主键去做防重表的唯一索引,比如使用订单号作为防重表的唯一索引,每一次请求都根据订单号向防重表中插入一条数据,插入成功说明可以处理后面的业务,当处理完业务逻辑之后删除防重表中的订单号数据,后续如果有重复请求,则会因为防重表唯一索引原因导致插入失败,直接返回操作失败,直到第一次请求返回结果,可以看出防重表作用就是加锁的功能。
注: 最好结合状态机幂等先判断一下

  1. 缓冲队列

将请求都快速地接收下来后放入缓冲队列中,后续使用异步任务处理队列中的数据,过滤掉重复的请求,该解决方案优点是同步处理改成异步处理、高吞吐量,缺点则是不能及时地返回请求结果,需要后续轮询得处理结果。

  1. 全局唯一号

比如通过source来源 + 唯一序列号传入给后端,后端来判断请求是否重复,在并发时只能处理一个请求,其他相同并发请求要么返回请求重复,要么等待 前面请求执行完成后再执行。

参考:

【1】:什么是接口的幂等性,如何实现接口幂等性?一文搞定
【2】:分布式系统中接口的幂等性
【3】:高并发下接口幂等性解决方案

什么是接口幂等性?为什么会产生接口幂等性问题?如何保证接口幂等性?相关推荐

  1. 高并发下如何保证接口的幂等性?

    前言 接口幂等性问题,对于开发人员来说,是一个跟语言无关的公共问题.本文分享了一些解决这类问题非常实用的办法,绝大部分内容我在项目中实践过的,给有需要的小伙伴一个参考. 不知道你有没有遇到过这些场景: ...

  2. 高并发下如何保证接口的幂等性

    前言 接口幂等性问题,对于开发人员来说,是一个跟语言无关的公共问题.本文分享了一些 ,绝大部分内容我在项目中实践过的,给有需要的小伙伴一个参考. 不知道你有没有遇到过这些场景: 有时我们在填写某些 f ...

  3. 如何保证接口的幂等性?

    什么是幂等性?所谓幂等,就是任意多次执行所产生的影响均与一次执行的影响相同. 为什么会产生接口幂等性问题 在计算机应用中,可能遇到网络抖动,临时故障,或者服务调用失败,尤其是分布式系统中,接口调用失败 ...

  4. 什么是接口幂等性?为什么会产生这个问题?如何保证接口幂等性?

    作者:三分恶 原文链接:https://cnblogs.com/three-fighter/p/14054749.html 博主负责的项目报了一个问题,用户操作回退失效.我们的设计里,操作回退是回到操 ...

  5. redis 判断存在性_Redis如何保证接口的幂等性?

    原标题:Redis如何保证接口的幂等性? 在最近的一次业务升级中,遇到这样一个问题,我们设计了新的账户体系,需要在用户将应用升级之后将原来账户的数据手动的同步过来,就是需要用户自己去触发同步按钮进行同 ...

  6. springboot幂等性_如何使用 SpringBoot + Redis 优雅的解决接口幂等性问题

    前言: 在实际的开发项目中,一个对外暴露的接口往往会面临,瞬间大量的重复的请求提交,如果想过滤掉重复请求造成对业务的伤害,那就需要实现幂等! 我们来解释一下幂等的概念: 任意多次执行所产生的影响均与一 ...

  7. 如何保证接口的幂等性

    如何保证接口的幂等性 什么是幂等性 幂等性是系统服务对外一种承诺,承诺只要调用接口成功,外部多次调用对系统的影响是一致的.声明为幂等的服务会认为外部调用失败是常态,并且失败之后必然会有重试. 通俗地说 ...

  8. springboot幂等性_Spring Boot + Redis + 注解 + 拦截器来实现接口幂等性校验

    一.概念 幂等性, 通俗的说就是一个接口, 多次发起同一个请求, 必须保证操作只能执行一次 比如:订单接口, 不能多次创建订单 支付接口, 重复支付同一笔订单只能扣一次钱 支付宝回调接口, 可能会多次 ...

  9. 如何保证接口幂等性?

    文章目录 1. 为什么要保证幂等性? 2. 如何保证接口幂等性 ①:数据库唯一主键 ②:CAS乐观锁机制 - 数据版本号 ③:防重 Token 令牌 ④:请求时携带唯一序列号ID ⑤:加本地锁 或 分 ...

  10. 【接口幂等性】使用token,Redis保证接口幂等性

    使用token保证接口幂等性 接口幂等性就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用. 举个最简单的例子,那就是支付,用户购买商品后支付,支付扣款成功, ...

最新文章

  1. ios NSLayoutConstraint
  2. c++容器vector
  3. lucene 范围过滤
  4. python绘制k线图的步骤_Python使用PyQtGraph绘制股票行情K线图
  5. Prism4文档翻译(第四章 第二部分)
  6. Mingw下g++编译执行顺序错误
  7. 【Codeforces - 977D】Divide by three, multiply by two(思维构造)
  8. java三国群雄_三国群英-真三国无双
  9. qt-opensource-windows-x86-vs2010-4.8.6 + qt-creator-windows-opensource-2.8.0
  10. 使用Mono Runtime Bundle制作安装包让C#桌面应用程序脱离net framework
  11. 非法关机linux分辨率丢失,非法关机造成文件系统损坏,怎么办?请教:附图片...
  12. DSA_常用10种算法(java数据结构与算法)
  13. 数组排序和集合排序的使用
  14. css过渡、动画3D环绕相册
  15. 让局域网网速极速狂飙(组图)
  16. 微信小程序云开发如何实现上传视频 以及 图片
  17. 北漂生活第十八弹-日子还照旧
  18. java程序步骤_java编写程序的步骤是什么?java编写程序步骤实例讲解
  19. 初见 http 401------谈谈401和403的区别
  20. 改名换姓的Java字节码压缩包

热门文章

  1. 集体智慧编程学习之核方法
  2. Javascript 设计模式 单例
  3. vb.net 物联网助手exe 软件重构
  4. cesium fog雾特效参数设置
  5. AutoRunner的快捷菜单
  6. 业务知识与技术知识的积累同样重要
  7. 集装箱 扩展程序_工厂一平米集装箱公厕销售,供求信息
  8. 2017百度之星程序设计大赛 - 初赛(A)今夕何夕
  9. [游戏开发]Unity Profiler真机调试
  10. Unity3D热更新技术点——ToLua(下)