再谈电商之支付逻辑与坑
支付接口逻辑
三方支付
-
sm2加密传参、校验参数 校验防重令牌,防止重复提交 支付校验 获取分布式锁 校验预支付缓存 不存在:订单超时 校验支付缓存 不存在:首次/超时后调起支付 存在:校验此次支付和缓存,不一致需关闭之前三方支付 调起支付 发送消息到防掉单延迟队列 返回调起结果
接口逻辑说明
这里存在两个缓存:
-
预支付缓存,与延时队列取消订单时间一致,30min,缓存存在说明订单还未超时 支付缓存,调起三方支付缓存,5min,超时后三方支付通道也会关闭。
支付中存在的问题
以下问题只针对于同一个人来说
支付调起
不同端之间,PC和APP间重复支付
针对于不同端之间的操作,在接口上使用分布式锁,锁住当前用户的操作,防止多端重复类型操作。
不同支付方式间,既调起了微信又调起了支付宝
针对于不同支付方式,可以使用缓存的方式,缓存有效期和支付有效期同步,即缓存存在说明调起的支付还有效,当存在有效支付时,调起了其他类型支付,需要对之前的支付方式做关单处理(三方提供)然后使用新调起的支付作为此用户的支付缓存。 保证当前最多有一种支付方式存在于缓存中。
支付
多端同时支付
超时支付
三方支付调起时,有可选参数过期时间,当前时间超过此时间后扫码会显示此二维码失效,来防止可能得多次支付,压力存在于三方。
订单后续逻辑
支付回调
在防止了多次调起多次支付后,回调也存在坑,回调这个通知方式,由于是异步操作,就会存在不及时性,可能性很多,所以我们需要从多个方面进行限制。 首先讨论回调和订单超时问题,正常情况下:
-
订单支付成功 异步接收三方支付结果 订单的后续逻辑 延迟队列执行对订单是否超时处理
即支付回调在延时队列操作之后,若由于某些原因回调信息没有收到,导致系统误以为订单尚未支付,把订单修改为了未支付,出现了数据异常。 针对上述问题,
-
延迟队列操作时,需要验证三方是否支付、正在支付,再对订单进行关单,若已经支付,直接走后续支付成功逻辑。 当收到支付成功回调时,订单以变为未支付时,支付优先于一切,即便订单已变为取消状态也是需要更改为已支付,做支付成功逻辑。
支付问题解决方案
如何防止多端重复支付
对于同一用户来说,支付时获取分布式锁,当一端发起支付直到调起成功,其他端无法调起。
如何防止重复调起并支付
用户压时间点支付存在的问题
前提:当订单创建时,就会把订单放入延时队列,默认30min后取出把未支付的订单改为取消状态 场景:用户支付逻辑中,验证订单过期时未过期,支付回调时订单过期。(角度刁钻) 分析一下,此时操作订单的逻辑有两个,一是延时队列进行订单超时操作,二是支付成功回调操作。
-
回调在前,延时队列在后。没有影响,延时队列关单时校验三方支付状态。 延时队列在前,回调在后。以支付为中心,即便订单取消,也是可以更改为已支付走支付成功逻辑。
上述情况中发生概率还是存在的,对于极端情况做了一些梳理。
如何防止重复支付
这里讨论的场景时,当一个订单支付成功后,由于种种原因没有接收到支付成功信息,导致订单还是未支付状态,用户可以再次发起支付
订单手动取消
取消前需要根据缓存,去对应支付方做关单处理后才可以关闭,若显示已支付,则直接走支付成功后续逻辑。
