服务端如何防止重复支付
共 1487字,需浏览 3分钟
·
2021-12-26 00:12
1、五年工作经验总结 16 条的代码规范 2、突发!Apache Log4j2 报核弹级漏洞 3、都在建议你不要直接使用 @Async 注解,为什么? 4、面试官:抛开Spring来说,如何自己实现Spring AOP? 5、蓝绿发布、滚动发布、灰度发布,有什么区别?这下明白了
概述
如图是一个简化的下单流程,首先是提交订单,然后是支付。支付的话,一般是走支付网关(支付中心),然后支付中心与第三方支付渠道(微信、支付宝、银联)交互,支付成功以后,异步通知支付中心,支付中心更新自身支付订单状态,再通知业务应用,各业务再更新各自订单状态。
这个过程中经常可能遇到的问题是掉单,无论是超时未收到回调通知也好,还是程序自身报错也好,总之由于各种各样的原因,没有如期收到通知并正确的处理后续逻辑等等,都会造成用户支付成功了,但是服务端这边订单状态没更新,这个时候有可能产生投诉,或者用户重复支付。
由于③⑤造成的掉单称之为外部掉单,由④⑥造成的掉单我们称之为内部掉单
为了防止掉单,这里可以这样处理:
1、支付订单增加一个中间状态“支付中”,当同一个订单去支付的时候,先检查有没有状态为“支付中”的支付流水,当然支付(prepay)的时候要加个锁。支付完成以后更新支付流水状态的时候再讲其改成“支付成功”状态。
2、支付中心这边要自己定义一个超时时间(比如:30秒),在此时间范围内如果没有收到支付成功回调,则应调用接口主动查询支付结果,比如10s、20s、30s查一次,如果在最大查询次数内没有查到结果,应做异常处理
3、支付中心收到支付结果以后,将结果同步给业务系统,可以发MQ,也可以直接调用,直接调用的话要加重试(比如:SpringBoot Retry)
4、无论是支付中心,还是业务应用,在接收支付结果通知时都要考虑接口幂等性,消息只处理一次,其余的忽略
5、业务应用也应做超时主动查询支付结果
对于上面说的超时主动查询可以在发起支付的时候将这些支付订单放到一张表中,用定时任务去扫
为了防止订单重复提交,可以这样处理:
1、创建订单的时候,用订单信息计算一个哈希值,判断redis中是否有key,有则不允许重复提交,没有则生成一个新key,放到redis中设置个过期时间,然后创建订单。其实就是在一段时间内不可重复相同的操作
附上微信支付最佳实践:
文章来源:https://cnblogs.com/cjsblog/p/14516909.html
最近热文阅读:
1、五年工作经验总结 16 条的代码规范 2、为什么我劝你放弃了Restful API? 3、Java8 Stream:2万字20个实例,玩转集合的筛选、归约、分组、聚合 4、公司规定所有接口都用 POST请求,这是为什么? 5、为什么阿里强制 boolean 类型变量不能使用 is 开头? 6、面试官:InnoDB中一棵B+树可以存放多少行数据? 7、MyBatis批量插入几千条数据,请慎用foreach 8、有了 for (;;) ,为什么还需要while (true) ?到底哪个更快? 9、名企公开挂“加班真好”标语,员工称一年被免费“白嫖”600多小时!网友看不下去了,稽查部门展开调查... 10、面试官:为什么 Java 不把基本类型放在堆中?我竟然答不上来。。 关注公众号,你想要的Java都在这里