网站权重如何合理分配,福州最好的网站建设公司,网站如何为关键词做外链,wordpress 禁止自动保存大家好#xff0c;我是磊哥#xff0c;想必大家对在线支付都不陌生#xff0c;今天和大家聊聊如何防止订单重复支付。看看订单支付流程我们来看看#xff0c;电商订单支付的简要流程#xff1a;订单钱包支付流程从下单/计算开始#xff1a;下单/结算#xff1a;这一步虽… 大家好我是磊哥想必大家对在线支付都不陌生今天和大家聊聊如何防止订单重复支付。看看订单支付流程我们来看看电商订单支付的简要流程订单钱包支付流程从下单/计算开始下单/结算这一步虽然不是直接的支付起点但是支付相关的金额等等信息都来自结算此时订单的状态是未支付申请支付用户选择申请支付客户端调用支付服务此时在系统内产生一笔支付流水这笔流水的状态是未支付发起支付支付服务调用三方支付通常这种钱包类的支付在发起支付这一步会响应一些支付的链接客户端会对链接进行对应的处理。钱包支付用户进行支付通常是通过对应的钱包进行的大家可以回忆一下自己在购物中支付的过程不同的端对钱包支付的处理是不太一样的京东PC端支付页APP端: 在国内购物大部分都是在APP端产品经理会想法设法把用户带到APP为什么我的示例图都用京东不用淘宝呢因为我拿UC打开淘宝会直接跳转APP。APP端的钱包支付我们应该都非常熟悉一般是拉起钱包支付。APP支付WAP端手机的网页站WAP端的支付一般是直接拉起对应的钱包如果拉起钱包失败就跳转界面京东支付WAP端PC端PC端通常是打开收银台展示一个二维码通过钱包扫码支付下面是京东的微信支付扫码页支付回调用户完成支付后三方支付平台会回调商户通知支付结果。同步订单状态支付服务在确认支付完成后会向订单服务同步支付的结果订单服务变更订单的状态由未支付-》待发货客户端通过轮询、长连接或者服务端主动推送的方式在界面上变更订单状态。我们再从支付流水的角度看一下支付状态的变化支付状态变化从未支付到有支付结果的终态中间还有一个中间状态支付中用户通过打开钱包--》完成支付--》支付回调这段时间的支付流水就处于支付中为什么要花这么多篇幅来讲支付的业务流程、交互过程呢因为我认为防止订单的重复支付不止是技术上的问题也是业务和产品上的问题。为什么订单会重复支付 未防重导致的重复支付 我们可以看到PC端支付是扫描二维码这些二维码就是对应相应的支付流水假如用户重复点击支付如果不做防重的的话会生成两笔支付流水也就是两个不同的二维码要是用户分别扫了两个不同的支付码那么毫无疑问就会产生重复支付。 掉单导致的重复支付 “我明明付款了为什么我的订单还没支付呢”黑我钱是吧这就是所谓的“掉单”外部掉单三方支付的支付状态没有同步或者没有及时同步到商城这叫外部掉单内部掉单支付服务的状态没有同步到订单或者客户端没有及时获取到订单状态这叫内部掉单。用户一看自己付了款结果商城里订单还未付款但是又特别想要可能就会再下一单这样就重复支付了。 多渠道导致的重复支付 我们国内支付的体验还是非常快捷的大家可能没有感觉如果了解过海外支付的可能了解很多支付的渠道消耗的时间非常长。比如用户保罗选择了一种支付方式Boleto结果支付的网点离保罗他们村太远了保罗又选择了Paypal支付保罗去赶集的时候又顺手去网点把Boleto的这一笔支付了结果就重复支付了。这种情况大家可能很少遇到我们可以用美团下一个单先打开微信支付不要支付啊接着回到美团打开支付宝用支付宝支付完成后用微信接着支付大家猜猜两笔支付是不是都能成功答案是可以。美团多渠道支付如何防止订单重复支付 加锁 不管是3.申请支付、还是5.支付回调,都应该以订单维度加锁防止并发下的重复操作。加锁毫无疑问也是分布式锁通常我们会选择Redis分布式锁。加锁 缓存结果 申请支付成功支付回调成功都应该缓存结果。再申请支付收到成功回调的时候都应该先去检查支付的状态。在这里插入图片描述 支付中流水取消 假如说用户重复支付了再次申请支付的时候如果已经申请支付成功了那么这笔支付肯定是要拒绝的。但是要是已经存在的这笔流水还在支付中呢——我们不确定它是成功还是失败肯定是不能拒绝支付的因为可能用户支付失败了但是状态还没同步这样肯定是不行的。所以我们可以取消掉正在支付中的流水再进行支付。支付中流水取消 已支付流水退款 现在又有新的问题了假如发起支付的时候有流水正在支付中如果第三方支付平台不支持取消支付或者用户新的支付是通过不同的渠道我们希望尽可能提高用户的支付成功率怎么办呢我们可以在发起支付的时候订单还在支付中的情况下允许用户发起多笔支付在支付回调的时候检查用户是否已经有成功流水对后来的流水进行退款处理。支付回调当然退款是个很危险的操作毕竟钱退了可就很难追回来一定要做好风险的控制。 主动轮询重试防止掉单 主动轮询防止外部掉单如果因为故障没有收到回调或者没有及时收到回调就可能会发生所谓的外部掉单。防止外部掉单的关键就在于不能傻傻地只等三方的回调通知而要主动去查询用户发起支付的3s之后就可以发起轮询了直到拿到支付流水的最终状态主动轮询一般可以这么实现轮询定时任务轮询使用定时任务扫描表中支付中的流水主动查询支付的状态定时任务的实现方式有很多线程池、调度框架、分布式调度框架等等。定时任务轮询的缺点有两个对数据库有一些压力观察监控会发现定时任务扫表的时候有时候会造成数据库的一些“峰刺”不便调整频率实际上用户发起一笔支付之后一般都会在10s-1min中完成支付越往后用户完成支付所以轮询梯度进行会更合理一些轮询的间隔可以设置成类似这种3s10s30s3min……延时消息轮询另外一种方式就是使用延时消息用户发起支付之后发送一个延时消息消费到延时消息之后查询流水支付状态没有拿到最终状态就再发一个延时消息。延时消息的好处是对数据库的压力没有那么大轮询的梯度也可以进行控制缺点是实现起来复杂一些而且要维护消息队列。同步异步防止内部掉单支付服务在收到异步通知回调、或者主动轮询到流水的最终状态后要通知订单服务支付流水的变化订单服务同步更新订单的状态这个过程要尽可能保证通知成功可以采用同步异步的方式。同步调用支付服务调用订单服务的通知接口有可能会因为网络等等的原因失败也可以重试但是根据经验如果网络出现一些波动重试很可能也会失败。异步通知支付服务还应该发送一个支付成功的消息订单服务可以利用消息队列的重试机制来尽可能保证支付状态的同步。这里还有一个问题客户端如何同步这个状态因为可能服务端更新了订单状态但是客户端的界面上还是未支付得用户主动刷新一下才能拿到最新的状态这样明显是不太合适的。服务端、客户端的状态同步无非就拉和推:拉很简单就是客户端在用户跳回订单状态页的时候轮询一会如果用户完成支付通常很短时间就能获取到状态的变更当然这种方式对客户端的性能会有一些影响而且很出现状态同步“漏网之鱼”的情况。推推的实现有些麻烦Web通常是用Websocket对APP端的推送一般采用第三方的推送平台。 客户端支付尽可能不外跳 不管从产品的角度还是技术的角度客户端发起支付这一步其实应该尽可能地不要外跳PC端使用支付服务生成的支付码而不是跳转移动端网页、APP在应用内展示支付页当然这个是由第三方支付平台决定的。在UC内内嵌支付宝不知道大家留意到了没有现在的支付宝已经做到了不用拉起钱包在应用内就可以完成支付这个对于商家的意义还是比较大的对用户体验、支付成功率都有正面的作用相信以国内的内卷程度其它支付供应商一定会“跟进”的。好了关于如何防止重复支付就讲到这里。对于支付老三也只是初窥门径希望各位大佬不吝指教。参考[1]. 服务端如何防止重复支付