服务端如何防止订单重复支付!

简介: 如图是一个简化的下单流程,首先是提交订单,然后是支付。支付的话,一般是走支付网关(支付中心),然后支付中心与第三方支付渠道(微信、支付宝、银联)交互。支付成功以后,异步通知支付中心,支付中心更新自身支付订单状态,再通知业务应用,各业务再更新各自订单状态。

概述

image.png

如图是一个简化的下单流程,首先是提交订单,然后是支付。

支付的话,一般是走支付网关(支付中心),然后支付中心与第三方支付渠道(微信、支付宝、银联)交互。

支付成功以后,异步通知支付中心,支付中心更新自身支付订单状态,再通知业务应用,各业务再更新各自订单状态。

这个过程中经常可能遇到的问题是掉单,无论是超时未收到回调通知也好,还是程序自身报错也好。

总之由于各种各样的原因,没有如期收到通知并正确的处理后续逻辑等等,都会造成用户支付成功了,但是服务端这边订单状态没更新。

这个时候有可能产生投诉,或者用户重复支付。

由于③⑤造成的掉单称之为外部掉单,由④⑥造成的掉单我们称之为内部掉单

为了防止掉单,这里可以这样处理:

1、支付订单增加一个中间状态“支付中”,当同一个订单去支付的时候,先检查有没有状态为“支付中”的支付流水,当然支付(prepay)的时候要加个锁。支付完成以后更新支付流水状态的时候再讲其改成“支付成功”状态。

2、支付中心这边要自己定义一个超时时间(比如:30秒),在此时间范围内如果没有收到支付成功回调,则应调用接口主动查询支付结果,比如10s、20s、30s查一次,如果在最大查询次数内没有查到结果,应做异常处理

3、支付中心收到支付结果以后,将结果同步给业务系统,可以发MQ,也可以直接调用,直接调用的话要加重试(比如:SpringBoot Retry)

4、无论是支付中心,还是业务应用,在接收支付结果通知时都要考虑接口幂等性,消息只处理一次,其余的忽略

5、业务应用也应做超时主动查询支付结果

对于上面说的超时主动查询可以在发起支付的时候将这些支付订单放到一张表中,用定时任务去扫

为了防止订单重复提交,可以这样处理:

1、创建订单的时候,用订单信息计算一个哈希值,判断redis中是否有key,有则不允许重复提交,没有则生成一个新key,放到redis中设置个过期时间,然后创建订单。

其实就是在一段时间内不可重复相同的操作

附上微信支付最佳实践:

image.png

相关文章
如何实现一个项目配置多个商户信息付款给对应商户
说明:本帖主要说明如何实现给一个平台配置多个商户的号实现多个商户收款。主要用于没有门店和第三方授权方式 支付宝最终是根据请求过来的appid来判断哪一个商户收款(也就是请求是谁的appid就收款到谁的账号下)    方案一:      1.
1289 0
|
10月前
|
存储 NoSQL Redis
下单接口防重提交问题
下单接口防重提交问题
|
消息中间件 Java 程序员
订单支付超时,自动关闭订单实现
今天跟大家一起探讨一个场景:用户对商品下单,约定30分钟没支付,超时订单将被系统自动关闭。
344 0
订单支付超时,自动关闭订单实现
|
弹性计算
阿里云存在未支付订单导致无法下单解决方法
解决阿里云存在未支付订单请支付或作废后再下单,阿里云服务器或其他云资源无法立即购买,提示“您选择的资源存在未支付订单,请支付或作废后再下单!”什么原因?这是由于你的阿里云账号之前已经创建了该订单,只是订单没有支付,所以无法再次创建订单。解决方法是,要么取消之前的订单,要么支付之前的订单。阿里云百科来详细说下阿里云账号下存在未支付订单的解决方法:
733 0
阿里云存在未支付订单导致无法下单解决方法
|
前端开发 应用服务中间件 API
订单异步通知修改订单状态
订单异步通知修改订单状态
订单异步通知修改订单状态
|
消息中间件 数据库 RocketMQ
创建支付订单流程|学习笔记
快速学习创建支付订单流程
278 0
创建支付订单流程|学习笔记
|
消息中间件 Dubbo 测试技术
Rest 方式测试支付下单和支付回调|学习笔记
快速学习 Rest 方式测试支付下单和支付回调
163 0
Rest 方式测试支付下单和支付回调|学习笔记
|
消息中间件 算法 Java
创建支付订单实现|学习笔记
快速学习创建支付订单实现
91 0
创建支付订单实现|学习笔记
|
消息中间件 数据库 RocketMQ
校验订单实现|学习笔记
快速学习校验订单实现
295 0
校验订单实现|学习笔记
|
消息中间件 Java RocketMQ
支付业务服务端测试|学习笔记
快速学习支付业务服务端测试
81 0
支付业务服务端测试|学习笔记