前言
“我正在参加「掘金·启航计划」”
🍊作者简介: 不肯过江东丶,一个来自二线城市的程序员,致力于用“猥琐”办法解决繁琐问题,让复杂的问题变得通俗易懂。
🍊支持作者: 点赞👍、关注💖、留言💌~
最近大聪明加入了一个智慧运输平台建设的项目组(下面就简称运输平台),在运输平台中除了运输板块的功能以外,最重要的就是支付模块的功能,毕竟涉及到了金钱💴的交易,所以要尽可能的做到万无一失。关于支付模块的功能,我们经常听到两个问题“掉单”和“重复支付”,他们都是支付过程中的大问题,我们也要尽可能的避免此类问题的出现。那么今天大聪明就和大家分享一下,如何有效的在支付模块中避免出现“掉单”和“重复支付”的问题。
掉单
首先我们先了解一下什么是掉单👇
所谓的掉单,就是用户完成了支付操作后回到平台一看,结果订单还是未支付的状态……😶
毫无疑问,只要出现了这种情况,用户肯定会原地“爆炸”,结果不是被投诉,就是被差评,甚至还会扣工资😂。接下来我们一起来看看掉单是如何产生的...
掉单的如何产生的
首先我们先了解一下完整的支付流程👇
- 用户在平台点击支付,客户端向服务端发起支付请求,同时创建对应的订单
- 支付服务会向第三方的支付渠道发起支付请求,并响应对应的url
- 用户执行实际支付操作(确认金额、输入)
- 用户完成支付后,跳转回平台
- 平台轮询订单服务,获取订单状态
- 支付渠道回调支付服务,通知支付结果
- 支付服务通知订单服务,更新订单状态
对于支付订单而言,大概可以分为这么几个状态:
- 待支付:用户未点击支付按钮,或用户在点击支付之后,支付服务请求支付渠道之前,处于未支付状态
- 支付中:用户发起支付后,再到完成支付,支付服务获取到最终支付结果之间,属于支付中状态。这个状态下,可以说是一个未知状态,平台对于用户的支付结果是不确定的
- 支付成功/支付失败:平台最终确定了用户在第三方的支付最终结果
我们会过头看支付的流程,貌似是没什么问题,那为什么会产生掉单的问题呢?
原因也很简单,就是支付的状态没有同步到,或者没有及时同步到。比如支付渠道的支付回调过程中发生了一些异常,导致没收到回调通知(外部因素,也叫外部掉单);支付服务通知订单服务中发生异常导致订单服务未收到通知(内部因素,也叫内部掉单);还可能会在轮询时间内没有获取到订单状态,结果用户看到未支付(内部因素,也叫内部掉单)。
如何避免掉单的产生
我们已经知道了掉单的产生原因,接下来我们一起来看看如何避免掉单的产生。
🍋如何防止内部掉单🍋
① 支付服务调用订单服务的时候,要增加重试机制(比如第一次未调用成功,接下来继续重试,直到调用成功为止,一般是重试三次),防止网络抖动情况下的调用失败。
② 我们可以采用异步的方式进行通知,支付服务投递一个支付成功消息,订单服务消费支付成功消息。当然了,整个过程要尽可能保证可靠性,例如订单服务要在完成订单状态更新后再确认完成消息消费。
🍋如何防止外部掉单🍋
外部掉单的因素就比较多了,比如网络因素、第三方服务因素等等,我们能做到的就是:“稳住内部为前提,主动查询外部服务”。如果只是等待第三方的回调通知,风险还是比较大的,支付服务要主动向第三方查询支付状态,即使有什么异常,也能及时感知到。比如可以使用定时任务,去查询支付状态为待支付的订单所对应的支付结果;或者使用延时消息队列去查询(完成支付后,把支付订单数据写到延时消息队列,让消息队列在若干秒后去查询支付结果)
重复支付
说完掉单,我们再看看重复支付。重复支付就比较好理解了,说白了就是用户发起了两次支付请求,如果一旦用户真的付了两次款,估计用户就不止原地爆炸这么简单了😂
出现重复支付的主要原因就是用户点击了两次支付按钮,导致向服务端发起了两次支付请求,从而出现重复支付。那么我们针对此类问题可以有两种解决办法👇:
- 支付按钮置灰。也就是当用户点击完支付按钮后,在一段时间内不允许用户第二次点击按钮。
- 在支付接口中增加相关校验。比如我们可以根据用户传递过来的参数,通过一系列的算法生成一串唯一编码,然后将编码放到 Redis 中,在后续的支付请求中,先去 Redis 中查询一次,如果查询出了结果,也就证明本次请求为重复支付。
重复支付的产生原因和解决办法也都非常简单,这里就一笔带过了,相信大家都可以理解😀
小结
本人经验有限,有些地方可能讲的没有特别到位,如果您在阅读的时候想到了什么问题,欢迎在评论区留言,我们后续再一一探讨🙇
希望各位小伙伴动动自己可爱的小手,来一波点赞+关注 (✿◡‿◡) 让更多小伙伴看到这篇文章~ 蟹蟹呦(●'◡'●)
如果文章中有错误,欢迎大家留言指正;若您有更好、更独到的理解,欢迎您在留言区留下您的宝贵想法。
爱你所爱 行你所行 听从你心 无问东西