支付系统 - 支付整体架构设计

6,421 阅读8分钟

本文先从一个宏观的视角,介绍支付平台整体设计,希望读者在阅读完本篇幅后,能对支付平台有个整体的认知。以下将从三个方面入手:

  1. 支付业务架构
  2. 支付流程分析
  3. 核心逻辑梳理

一、支付业务架构

我们先来看看京东支付整体架构设计:

京东支付平台架构设计
京东支付平台架构设计

京东支付的设计算是中规中矩没有什么与众不同之处,这张图来自互联网公开资料,内部实现和图中的出入我们无从得知。但是,大部分的系统设计都是通过借鉴别人分享的内容自己摸索软件应有的架构。

本专栏是以做工程的角度去介绍支付系统,肯定不可能描述这么大而全的系统,相信对大部分的程序设计人员而言,系统设计做完写代码只是随手之做。程序写的好不好很大程度取决于开发者自身的能力,只要设计没大的偏差,基本上都只是工作量的问题。所以这里一个相对简单“五脏俱全”的系统对我们来说更有意义。一图胜千言,需要注意的是图中是对专栏中会带着读者实现的内容进行了描述。后续文章不会提及的部分并没有出现在图中。比如清结算,对账,报表,交易账单等。并不是支付体系中不包含这些部分,相反这些部分是非常重要的内容。

支付网关架构
支付网关架构

如果读者需要对支付体系有近一步深入的了解,建议大家可以阅读 Ping++出品的支付知识平台凤凰牌老熊 系列相关文章。

二、支付流程分析

我们看一下微信扫码支付的时序图,来自微信支付商户后台。

微信扫码时序图
微信扫码时序图

业务流程说明:

(1)商户后台系统根据用户选购的商品生成订单。
(2)用户确认支付后调用微信支付【统一下单API】生成预支付交易;
(3)微信支付系统收到请求后生成预支付交易单,并返回交易会话的二维码链接code_url。
(4)商户后台系统根据返回的code_url生成二维码。
(5)用户打开微信“扫一扫”扫描二维码,微信客户端将扫码内容发送到微信支付系统。
(6)微信支付系统收到客户端请求,验证链接有效性后发起用户支付,要求用户授权。
(7)用户在微信客户端输入密码,确认支付后,微信客户端提交授权。
(8)微信支付系统根据用户授权完成支付交易。
(9)微信支付系统完成支付交易后给微信客户端返回交易结果,并将交易结果通过短信、微信消息提示用户。微信客户端展示支付交易结果页面。
(10)微信支付系统通过发送异步消息通知商户后台系统支付结果。商户后台系统需回复接收情况,通知微信后台系统不再发送该单的支付通知。
(11)未收到支付通知的情况,商户后台系统调用【查询订单API】。
(12)商户确认订单已支付后给用户发货。

OK,看到这里相信读者对用户-微信支付交互的流程有了一定的理解,上图中的商户后台系统指的就是我们现在要开发的系统(为了描述方便,以下使用支付系统指代)。在以上时序图中,我们重点关注第 10 步【异步通知商户支付结果】和第 11 步【调用查询订单 API】。聪明的同学可能已经想到了,对用户而言支付过程是同步的,对服务端而言支付过程是异步的。为了更好的理解这种设计,我们先来看看

当用户扫描二维码时发生了什么:

其实特别简单,支付系统通过 HTTP 请求微信接口,微信返回二维码字符串,格式类似 weixin://wxpay/bizpayurl?pr=A7XXXXXV 。本质上是一个短链接,转换为原始链接后里面会有mch_idappid等信息,微信自然就知道这是哪个商户创建的支付订单。我们利用二维码生成工具将这个字符串变成图片。用户打开微信扫码,微信客户端协议(其实也是个浏览器)解析二维码向微信支付系统发出请求,微信进行一系列的验证返回 OK,微信客户端的支付控件要求输入密码,用户正确输入密码控件再次向微信支付服务端发起确认支付请求。最后,微信支付服务端接收到确认支付请求后,你可以简单的理解为根据支付订单的信息创建一笔转账请求,如此这就转变成了微信内部的异步结算流程。页面提示支付成功,流程结束。

我们可以很自然的想到,当微信控件提示支付成功仅仅代表微信内部创建了异步结算流程。也就是说,最终支付结果需要微信通知,或者我们主动去查询。扩展到其他支付模式,比如 APP 支付开发人员需要集成微信 SDK,一般都会实现 onResp 函数。支付完成后,微信 APP 会返回到商户 APP 并回调 onResp 函数,很多人同学在这里直接认为是支付成功,其实这是很不严谨的。我们看看微信 APP 开发手册怎么说:

参照微信 SDK Sample,在类实现 onResp 函数,支付完成后,微信 APP 会返回到商户 APP 并回调 onResp 函数,开发者需要在该函数中接收通知,判断返回错误码,如果支付成功则去后台查询支付结果再展示用户实际支付结果。注意:一定不能以客户端返回作为用户支付的结果,应以服务器端的接收的支付通知或查询API返回的结果为准。

但是,一般而言微信控件返回的支付成功绝大多数情况都是和最终通知的结果一致的,只有极少数情况不一致,说实话不一致的情况我也没有遇到过。不过我还是建议严格按照微信支付的要求去做,原因有二:

  1. 如果是业务量过小,可能短期内不会遇到不一致的情况,如果接口升级等因素可能会导致大量不一致的情况。到时候微信强制要求整改不如一次到位。
  2. onResp 函数回调后主动查询支付结果,可快速保证自己的业务系统和支付系统支付状态一致性。避免因为微信通知延迟导致的短暂状态不一致问题。否则用户在 APP 上看到现象是,提示支付成功,但是账单依然显示未支付。当然这里的实现可能是,APP 调用业务系统查询接口-业务系统调用支付系统-支付系统请求微信查询支付结果。同步请求一路返回最终业务系统中的业务账单也会更新,极大的减少了用户重复支付的可能性。

三、核心逻辑梳理

看了上面的支付流程图,可能大家对我们要设计的支付系统调用链还不是很清楚,因为并没有体现下游系统和支付系统之间的关系。为了说明这个问题,我简单的画了图,还是以扫码支付举例。

充值流程
充值流程

上面的场景假设用户需要购买会员业务。

  • 业务系统内部创建一笔充值流水,并通过 HTTP 请求支付系统
  • 支付系统接收到请求后进行一系列内部处理,最终路由到某支付通道请求微信获取二维码字符串
  • 下游业务系统接收到字符串并向用户展示

OK,整个流程分析完了,可以看到下游业务系统的充值记录此时和支付系统的支付订单状态都为待支付。下面我们来分析用户扫码支付后情况。

充值成功流程
充值成功流程

如上所述,用户扫码支付成功后只需要稍等片刻即可发现会员购买成功了。这张图里忽略了支付系统中容错处理的部分,如网络原因三方渠道的异步阶梯通知,支付系统的定时查证流程。

这两张图看着都非常简单,简单的背后是因为我们省略了很多内部处理的逻辑。其实,支付系统中设计到的身份认证,签名、加解密、流控、熔断、补偿、对账、差错处理以及一些标准化的东西都需要很大的篇幅去介绍,这里就先简单的略过。

通过以上分析,希望读者能对支付平台有个整体的认知,后续会从工程设计的角度去讨论这些问题。