日前应公司业务发展的要求,对支付逻辑进行了拆分,形成了独立支付服务。本文基于服务拆分的实践,探讨建立独立支付服务的思路。
文末的关键编码,为处理后的伪代码,与实际项目无关,特此声明。
一:什么是独立支付服务
假设有三个不同的项目A,B,C,都需要接入支付宝H5支付功能。按照以往的开发模式,这三个项目需要分别开发一套与支付宝的对话逻辑,包括下单、支付回调、订单支付状态查询等。
假设这三个项目,现在要接入微信H5支付和微信JSAPI支付,那么同理,他们需要分别开发一套与微信方的对话逻辑。
如果还需要接入其他的支付方式呢?
独立支付服务可以理解为这些支付方式的代理,A,B,C在独立支付服务中注册它们的关键支付参数及商品,独立支付服务提供支付流程的保证和在关键的时间节点(订单创建、订单支付成功等)的通知。
有了独立支付服务,不管有多少个项目,大家都不需要关注与微信方等的对话逻辑,只需要关注必要的配置及少数几个通知就可以了。
二:支付服务应包含哪些功能
- 客户管理。提供客户的注册、鉴权、关键支付信息(如微信appid)等的存储。
- 商品管理。客户创建商品、修改商品价格、设置各种通知接口。
- 支付服务。封装与实际支付服务提供者(微信、支付宝)的交互,提供统一的预下单接口,并在关键的时间节点通知客户。
- 查询服务。客户主动查询某订单的支付状态。
三:支付的整体流程是什么
假设支付平台的服务器为S,客户的服务器为s,客户的前端(支付按钮所在的地方)为c。
假设客户A已经在支付平台注册了商品a,并设置当a创建订单和支付成功的时候,都要通知给s。
以支付宝H5支付为例。
当用户点击支付按钮之后,支付流程应该是这样的:
- c->S:用户要支付啦,选的是支付宝H5支付,商品是a,数量是1,用户的唯一标识是“15705420001” ,需要带给s那货的信息是"xxxxxx";
- S->c:我和支付宝方沟通过了,订单已创建,你的支付参数是*****,订单标识为12345;
- S->s:有用户创建订单啦,用户是“15705420001”,商品是a,数量是1,你的客户端托我给你带的话是‘xxxxxx’,订单标识是12345;
- c :用支付参数一顿操作,唤起了支付,用户付款;
- 支付宝->S:订单12345支付成功啦;
- S->s: 有用户支付订单啦,用户是“15705420001”,商品是a,数量是1,你的客户端托我给你带的话是‘xxxxxx’,订单标识是12345;
- s:记录用户15705420001,买了1个商品a;
如果s不相信支付成功的通知呢?
- s->S: 这个订单12345的,确实支付了吗?你去支付宝问问;
- S->s:问过支付宝了,支付了;
- s:记录用户15705420001,买了1个商品a;
c从支付宝的支付页面返回之后
- c->S:麻烦看下12345支付成功了吗;
- S->c:问过支付宝了,支付了;
- c:跳转支付成功页面;
四:关键编码
笔者实践采用的是koa+mysql+redis技术栈,关键编码依然以支付宝h5支付为例。
4.1:支付宝h5支付
- 获取支付参数时
const info = await aliH5PayChannel.unifiedOrder(goodsInfo);
await notifyOrderCreated(goodsInfo, info);
- 用户支付成功后
//支付结果通知逻辑
await notifyPaySuccess(payOrder);
- 查询订单
if (orderType == ORDERTYPE.ALIH5PAY) {
let queryResult = await aliH5PayChannel.queryOrder(orderNo);
// ...
}