工作中的点点滴滴接口幂等的问题

背景

  最近上线了一套官网的大客户运营系统,其中有个功能是运营人员可以直接通过这个平台给客户下单,生成好的订单,再让高级权限人员审核,我们再通过订单系统接口推送给订单系统进行生成履约等环节。订单接口返回成功,我们会把我们系统的订单状态标记为“生产中”,订单接口返回失败我们标记为“生产失败”。然后在上线运行的时候发现了一个问题就是有一个订单,是明明已经推送给了订单系统中,但是在我们这边显示的“生产失败”。然后通过日志信息发现,这笔订单调用了两次订单系统的接口,第一次调用成功,订单标记为“生产中”,第二次调用失败,订单系统返回当前订单已经存在,然后我们系统判断调用失败,订单标记为“生产失败”。然后追踪原因发现订单那审核接口调用了两次,导致了这个问题的产生。至于为什么会调用两次这里就不再追究。通过这个问题我们发现同一个业务单据调用同一个接口如果要保证结果的一致,那么这个接口就需要做幂等,查看百度百科上对幂等的定义其实基本上也和这个差不多。

  当然上面我遇到的这个场景除外,比如像订单支付,同一个订单支付多次,然后多次扣款,那客户还不提着50m大刀赶过来了呀。另外一种常见的场景就是Mq消息在消费的时候遇到重复消费的场景,像这种情况也是需要做接口幂等的,要不然数据肯定会有脏数据问题了。

保证幂等性的几种方式

  • 对于新增订单这种类似的接口。前端连续多次点击提交按钮疯狂的调用新建订单接口,像这种情况就可以使用接口参上加上token的机制来实现防止数据接口重复提交。最简单直接的实现方式就是在提交订单接口前面调用获取一次token,在获取token的服务端接口里面生成token的同时还需要把这个token给保存起来,然后客户端在调用新建订单接口的时候带上这个token来访问,服务端获取到这个token,判断一下这个token是否存在,如果存在则表示第一次提交,放行请求,并且删掉这个token。相反的,如果token不存在,就代表是重复请求,不需要进行业务处理,返回给前端一个重复的标记即可。

  • 对于新增数据的这种情况,还可以通过数据库的唯一性索引来处理。防止数据重复提交。

  • 针对像上面我遇到的那种场景是数据修改数据的情况,类似这种的,可以使用状态机来保住接口幂等性。就用我们那个订单例子,他的流程就有创建中,创建完成,待审批,生产中,生成完成,生产失败等,生产中的前置状态那么只能是待审批,生产失败的前置状态也只能是待审批,就是说这个订单如果想变成生产失败,那么它就只能从待审批这个状态过来。所以通过这种状态机的流转我们就可以控制请求的幂等。

  • 像MQ这种重复消费的情况,一般在使用mq的业务场景,我们都保存一下mq消息的唯一key,然后把这个唯一key存在数据或者redis里面,在消费的业务处理方法里面判断一下这个消息key是否存在,如果已经存在,就表示已经消费过了 ,相反的就表示可以正常放行处理。

原文地址:https://www.cnblogs.com/yangkangIT/p/5825094.html