文本
在支付系统中,支付网关与支付通道的连接是核心功能。支付网关是对外提供服务的接口。所有需要渠道支持的资金操作都需要通过网关分发到相应的渠道模块。一旦设定,后续行动就很少,而且很难调整。支付通道模块接收网关的请求,调用通道接口进行真实的资金操作。每个通道的接口和传输方式都不同,所以这里支付网关相对于支付通道模块的作用就类似于设计模式中的,封装各个通道的差异,向网关呈现统一的接口。网关的作用是为业务提供通用的接口,一些与通道交互的公共操作也会放在网关中。
支付网关在支付系统参考架构图中的位置如下所示:
1 功能概述
支付系统向其他系统特别是交易系统提供支付服务,包括签单、支付、退款、充值、转账和取消等。有些地方还会额外提供签单支付的接口,支持支付过程中的卡绑定。各个服务实现的流程基本相似,包括下单、取消订单、退货、查看订单等操作。每个操作实现包括参数验证、支付路由、订单生成、风险评估、调用渠道服务、更新订单、发送消息七个步骤。对于一些比较复杂的通道服务,还涉及到异步通知处理。步。
一般来说,主要的支付流程会涉及以下几个模块:
不同类型的支付产品会有不同的外部接口。随后将分类别介绍各类支付产品的设计。这里重点介绍支付(API)网关的设计以及支付产品的整体流程实现。基于微服务架构描述了软件架构的设计。
2 支付(API)网关
支付网关是直接连接业务系统的接口。它本身不执行任何与支付相关的业务逻辑。它把支付产品接口中与业务无关的功能提取出来,统一在这里实现。这样在具体的产品界面中就不需要考虑这些与业务无关的逻辑了。支付网关的设计还与外部接口参数有关。我们来看看业界几大主流支付平台的界面设计。
2.1 支付宝
对外接口使用统一参数,请参见《App支付请求参数说明》。接口参数分为三层:公共参数、业务参数、业务扩展参数。公共参数对于所有请求接口都是通用的。
业务相关的参数通过特定的规则进行拼接上传,最后由参数生成签名并放置在sign字段中。
支付宝的接口混合了json格式和格式。参数命名方面,有下划线和驼峰式两种。英语单词的使用也不是很规范。希望后续版本能够做得更好。
2.2 微信支付
与支付宝不同,微信支付使用XML格式进行消息传输。在其“接口文档说明”中,有对XML消息格式的详细说明。当然,也使用了签名字符串来保证接口的安全,签名结果放在sign标签下。
在界面设计方面,与支付宝还有一些差距。有些参数名称不一致,比如商户号,有些接口调用了。
2.3
是将支付涉及的对象,如支付宝、支付宝、卡等,以资源的形式呈现出来,并通过API支持操作的标准设计。

其定位和设计目标与国内第三方支付平台不同。它主要侧重于支持国际收入。对于国内应用来说,其易用性略逊于支付宝和微信支付,但一直是支付API设计的典范。
对于电商支付平台来说,其定位更接近于聚合支付。聚合多种支付方式,为公司各项业务提供支持。这里,支付网关和支付产品的设计尤为关键。合理的接口设计可以大大减少支付渠道对接的开发工作量。一般支付产品不会超过10个,但根据公司规模,支付渠道可能会超过100个。
3 设计原则
如上所述,支付网关、支付产品和支付渠道之间的职责分工是:
按照这样的分工,支付网关上实现的主要功能有:
支付产品提供以下功能:
在产品层或网关层可以实现以下功能:
4 签名及验证
API路由和接口安全是微服务的基本模式,本文不做介绍。有兴趣的同学可以参考相关资料。这里重点关注支付所需的签名和签名验证。
对接口进行签名是防止接口被盗用的重要手段。大多数第三方支付和银行接口签名规则是相似的。格式参数请参考支付宝签名流程。 XML格式请参考微信支付签名流程。事实上,两者是相似的,其签名和签名验证流程可以为支付系统服务器端与商户端的交互提供参考。
主流的加密算法有RSA、MD5、DES。支付宝使用RSA,微信支付使用MD5。
加密的常见过程是:
步骤 1:将各个参数连接成有序字符串。参数的格式为key=,按照key的字符顺序排序,并用&或其他符号连接。
appid:wxd930ea5d5a258f4f mch_id:10000100 device_info:1000 body:test nonce_str:ibuaiVcKdpRxkhJA
这种请求会被拼接成:
appid=wxd930ea5d5a258f4f&body=test&device_info=1000&mch_id=10000100&nonce_str=ibuaiVcKdpRxkhJA
步骤2:使用RSA对字符串进行签名,生成签名字符串。
cYmuUnKi5QdBsoZEAbMXVMmRWjsuUj%2By48A2DvWAVVBuYkiBj13CFDHu2vZQvmOfkjE0YqCUQE04kqm9Xg3tIX8tPeIGIFtsIyp%2FM45w1ZsDOiduBbduGtRo1XRsvAyVAv2hCrBLLrDI5Vi7uZZ66Lo5J0PpUUWwyQGt0M4cj8g%3D
步骤3:将签名字符串拼接到原始请求中,生成最终的字符串。
appid=wxd930ea5d5a258f4f&body=test&device_info=1000&mch_id=10000100&nonce_str=ibuaiVcKdpRxkhJA&sign=cYmuUnKi5QdBsoZEAbMXVMmRWjsuUj%2By48A2DvWAVVBuYkiBj13CFDHu2vZQvmOfkjE0YqCUQE04kqm9Xg3tIX8tPeIGIFtsIyp%2FM45w1ZsDOiduBbduGtRo1XRsvAyVAv2hCrBLLrDI5Vi7uZZ66Lo5J0PpUUWwyQGt0M4cj8g%3D
服务器收到该请求后,使用RSA公钥对sign字段进行解密。如果解密成功,则将解密结果与原始请求进行比较,看是否一致。如果使用MD5,则该过程用于对商户端和支付系统进行加密,以检查最终结果是否一致。