各支付场景下前后端交互流程

411次阅读  |  发布于3年以前

背景

支付有多种渠道,在不同的宿主环境下,可能都不一样,比如APP内的支付、微信内支付、小程序支付、浏览器内h5支付等等。这篇文章主要理清常见场景下各个支付的流程和api,后续一旦有新业务接入支付,能起到一个引导作用,少走弯路。

业务APP内支付

APP内,主流支付方式分两种:IAP支付和第三方支付。

IAPIn-App Purchase,即用户在业务APP内就能完成购买。排除支付过程中APP Crash等异常case,个人认为,体验相对于第三方支付更好。对虚拟商品,苹果强制APP使用IAP支付,否则不给过审。因此,很多APP采用其他的方式骗过审核,通过一个开关,在审核期间,打开开关启用IAP支付,审核过后启用第三方支付。不过这也有风险,一旦被苹果发现,APP可能会被下架。为什么不采用体验更好的IAP支付呢?原因可能跟苹果对每笔支付提成30%有关。当然,Android也是支持IAP的,如 Google Play、Amazon Appstore,不过Android的Appstore百花齐放,如果要支持IAP,就得支持非常多的Appstore,并且Appstore不一定支持了IAP能力,因此,Android内一般采用第三方支付。

第三方支付需要跳转到第三方APP才能完成支付行为,例如:微信和支付宝。

APP内的支付,不管是IAP还是第三方,都需要借助APP的能力,前端需通过jsbridge跟APP交互。当然,在APP里面直接使用h5支付也是没问题的。下面就看下这两种支付方式的详细流程

第三方支付

支付流程图如下:涉及5个关联方,用户、业务APP、业务server端、支付平台C端,支付平台server端。目前国内主要支付平台为微信和支付宝。详细流程如下:

  1. 用户发起支付
  2. 请求创建订单接口,获取订单id
  3. 通过订单id,业务server端请求支付平台server端下单接口,获取支付信息(主要是预支付订单prepay_id)
  4. 业务APP在获取到支付信息后,通过支付平台提供的SDK拉起APP,用户输入密码发起支付
  5. 支付平台server端通知业务平台server端支付状态
  6. 业务APP轮询获取支付状态

从上面来看完成整个支付流程前端需要做的事情如下:

  1. 调用业务创建订单接口,获取订单id
  2. 调用业务发起支付接口,获取支付信息
  3. 调用jsbridge,与客户端约定jsbridge(由客户端同学接入第三方支付提供的SDK),将支付信息传给客户端,由客户端拉起第三方支付平台并传递支付信息
  4. 获取支付状态,在成功调用jsbridge之后,就可以去服务端获取用户支付状态(轮询或websocket),根据支付状态给用户UI反馈

IAP

涉及4个关联方,用户、业务APP、业务server、Apple Appstore。详细流程如下:

  1. 首先在Appstore后台,创建IAP商品,获取IAP产品id,需要填写商品名称、简介、价格、销售范围等,这些信息在拉起支付弹窗的时候显示
  2. 将IAP产品id关联我们的商品id,给用户售卖的是我们的商品id
  3. 在C端售卖页,用户挑选商品,发起支付
  4. 业务server端创建订单,构造发起支付所需支付信息,包含当前商品id关联的IAP产品id
  5. 业务APP拿到支付信息后,通过Appstore提供的SDK提交支付信息
  6. 拉起支付弹窗,用户确认支付后,回调给业务APP支付票据
  7. 业务APP上传支付票据给业务server,这一步是必要的,得通知业务server用户支付了
  8. 业务server向Appstore验证支付票据是否有效,如果有效,server记录支付成功了
  9. 业务APP轮询业务server,获取用户支付状态

前端所要做的事情与上述第三方支付差不多,不再赘述。

区别

从上述分析来看,IAP和第三方支付的区别在于

支付方式 支付体验 系统支持 交易验证 开发体验 使用意愿
IAP支付 主流是IOS,Android虽然支持,但各个厂商不统一 用户支付成功后,交易验证由业务APP-> 业务server -> Appstore,主要在业务侧完成,由业务侧保证 差,需要关注的事情更多,如:支付完成后APP crash,下次重启要重新关注这个支付;交易验证是在用户和server间传递的,网络环境复杂,要引入重试机制 不太愿意,有交易抽成
第三方支付 中等 Android和IOS 用户支付成功后,交易验证由第三方server->业务server,主要由第三方保证 好,大量的事情由第三方完成 愿意

业务APP外支付

APP外支付,主要分微信内和微信外支付

微信内支付

指在微信APP内打开的h5,小程序,发起的支付行为。

h5支付

在微信APP内打开h5页面,能让用户购买商品、支付。整个支付流程跟业务APP内第三方支付流程类似,主要区别在于拉起支付的主体。APP内的第三方支付是由业务APP拉起第三方支付APP,如 微信、支付宝,但微信内打开的h5,使用的就是微信提供的jsapi能力(本质也是jsbridge)。下面说一下详细流程:

  1. 配置支付目录,最后请求拉起微信支付收银台的页面地址称之为“支付目录”,如果拉起支付的页面地址与配置的不一样,微信会提示“当前页面的URL未注册”
  2. 需要获取用户openid[1],业务server下单的时候需要,一旦获取到后,前端可以缓存起来,因为同一个用户在同一个appid下,openid是不会变的。
  3. 用户发起支付,同样业务server创建订单,从微信支付server获取预支付信息
  4. h5获取预支付信息后,结构为如下PayParam,调用微信提供的jsapi,代码如下,参考文档[2]。其中支付参数除appid外,其他的都有业务server返回
interface PayParam { 
  appId: string; // 公众号ID,由商户传入 
  timeStamp: string; // 时间戳,自1970年以来的秒数 
  nonceStr: string; // 随机串 
  package: string; 
  signType: string; // 微信签名方式: 
  paySign: string; 
} 

function onBridgeReady() { 
  const payParam: PayParam = { 
    appId: 'wx2421b1c4370ecxxx', // 公众号ID 
    timeStamp: '1395712654', // 时间戳,自1970年以来的秒数 
    nonceStr: 'e61463f8efa94090b1f366cccfbbb444', // 随机串 
    package: 'prepay_id=up_wx21201855730335ac86f8c43d1889123400', 
    signType: 'RSA', // 微信签名方式: 
    paySign: 
      'oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd7vaRvkYD7rthRAZ/X+QBhcCYL21N7cHCTUxbQ+EAt6Uy+lwSN22f5YZvI45MLko8Pfso0jm46v5hqcVwrk6uddkGuT+Cdvu4WBqDzaDjnNa5UK3GfE1Wfl2gHxIIY5lLdUgWFts17D4WuolLLkiFZV+JSHMvH7eaLdT9N5GBovBwu5yYKUR7skR8Fu+LozcSqQixnlEZUfyE55feLOQTUYzLmR9pNtPbPsu6WVhbNHMS3Ss2+AehHvz+n64GDmXxbX++IOBvm2olHu3PsOUGRwhudhVf7UcGcunXt8cqNjKNqZLhLw4jq/xDg==', // 微信签名 
  }; 
  WeixinJSBridge.invoke('getBrandWCPayRequest', payParam, function(res) { 
    if (res.err_msg === 'get_brand_wcpay_request:ok') { 
      // res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。 
      // 还是需要轮询业务服务端获取用户支付状态 
    } 
  }); 
} 
if (typeof WeixinJSBridge === 'undefined') { 
  if (document.addEventListener) { 
    document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false); 
  } else if (document.attachEvent) { 
    document.attachEvent('WeixinJSBridgeReady', onBridgeReady); 
    document.attachEvent('onWeixinJSBridgeReady', onBridgeReady); 
  } 
} else { 
  onBridgeReady(); 
} 

小程序支付

微信小程序的支付能力,跟h5支付的类似,不过比h5的jsapi支付接起来更简洁。

  1. 获取openid,小程序获取openid比h5要方便得多,详细可见wx.login[3]
  2. 户发起支付,同样业务server创建订单,从微信支付server获取预支付信息
  3. 小程序获取预支付信息后,调用wx.requestPayment,代码如下,参考文档[4]。
const payParam: PayParam = { 
    timeStamp: '1414561699', 
    nonceStr: '5K8264ILTKCH16CQ2502SI8ZNMTM67VS', 
    package: 'prepay_id=wx201410272009395522657a690389285100', 
    signType: 'RSA', 
    paySign: 
      'oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd7vaRvkYD7rthRAZ/X+QBhcCYL21N7cHCTUxbQ+EAt6Uy+lwSN22f5YZvI45MLko8Pfso0jm46v5hqcVwrk6uddkGuT+Cdvu4WBqDzaDjnNa5UK3GfE1Wfl2gHxIIY5lLdUgWFts17D4WuolLLkiFZV+JSHMvH7eaLdT9N5GBovBwu5yYKUR7skR8Fu+LozcSqQixnlEZUfyE55feLOQTUYzLmR9pNtPbPsu6WVhbNHMS3Ss2+AehHvz+n64GDmXxbX++IOBvm2olHu3PsOUGRwhudhVf7UcGcunXt8cqNjKNqZLhLw4jq/xDg==', 
  }; 
wx.requestPayment({ 
  ...payParam, 
  success: function(res) {}, 
  fail: function(res) {}, 
  complete: function(res) {}, 
}); 

微信外支付

主要场景为用户在手机浏览器打开网页,购买、发起支付,从外部浏览器唤起微信或者支付宝支付。这个场景的实现方式跟上述所有场景不同,以拉起微信支付为例,流程图如下:

涉及6个关联方,用户、浏览器、微信h5支付中间页、微信客户端、微信支付server端、业务server端。详细流程如下:

  1. 用户发起支付
  2. 请求创建订单接口,业务server端请求微信支付server端,获取微信支付中间页h5地址,示例:
//微信支付中间页
https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx162128390473563d952e4f371ca7d70000&package=2985141145&redirect_url=https%3A%2F%2Fwww.ggl.cn%2Feggl%2Fh5%2Fsale%2Fpay%2Fresult%3Forder_id%3D6974383092475680542
// 其中prepay_id、package等是支付相关参数,
// redirect_url就是支付成功、取消、超时返回浏览器要打开的页面地址

3 . 获取到微信支付中间页h5地址后打开这个页面,这个页面会检测支付网络环境,确认OK,通过deeplink的方式拉起微信APP,deeplink demo如下:

weixin://wap/pay?prepayid%3Dwx162128390473563d952e4f371ca7d70000&package=2985141145&noncestr=1623850119&sign=bfc799bb3c643e44c0a334b531b26b17

4 . 拉起微信支付弹窗,用户确认支付后,微信支付server端通知到业务server端用户支付状态

5 . 另一方面,打开支付中间件5s后,如果拉起中间页有传入redirect_url参数,就会打开redirect_url,否则返回发起支付的页面

6 . 从微信APP回到浏览器后,建议让用户选择是否支付,才开始轮询用户支付结果,因为无法保证支付中间页回跳时,支付流程已结束 最佳实践

基于以上支付流程,列举出常见支付场景及其最佳的支付方式

平台 IAP支付 第三方支付 jsapi支付 小程序支付 h5支付
业务APP内Android 支持,但需要兼容各个厂商 推荐 不支持 不支持 支持,但体验不好
业务APP内IOS 支持,体验好,但厂商会提成 推荐 不支持 不支持 支持,但体验不好
微信内h5 不支持 不支持 推荐 不支持 不支持
微信内小程序 不支持 不支持 不支持 推荐 不支持
微信外h5(浏览器场景) 不支持 不支持 不支持 不支持 推荐

Q&A

  1. 嵌入到小程序中的h5页面,能用h5原本的支付能力吗?应用场景,想直接复用原有h5做好的东西。

答:不可以,但是也有解决方案,只是体验没有小程序支付好,具体是在发起支付的时候通过window.wx.miniProgram.navigateTo这个api从h5跳转到小程序页面支付 2. h5支持在浏览器拉起微信和支付宝支付,嵌入业务APP,能正常发起支付吗?应用场景,不同APP中复用同一套h5售卖。

答:可以,但是可能需要客户端支持拦截第三方APP的deeplink,通用也不太好,如 拉起第三方支付APP后,取消支付无法返回原来的APP

参考资料

[1]需要获取用户openid: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_4

[2]参考文档: https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_3.shtml#part-6

[3]wx.login: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html

[4]参考文档: https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_2.shtml#part-6

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8