微信小程序支付
流程:
商户下单: 商户调用小程序支付API接口生成订单并获取预支付交易回话标识(prepay_id)
商户调起支付
商户小程序通过调用小程序提供的requestPayment方法来拉起微信收银台。
用户支付
用户在微信收银台完成支付/取消支付,返回商户小程序页面后,商户小程序页面将收到小程序提供的[requestPayment]方法返回的回调,此时商户需要调普通支付查询订单API接口确认订单状态,并根据订单状态展示支付结果。
同时,如果用户支付成功,微信支付系统会向商户发送[支付成功回调],未收到回调时,商户可调用[普通支付查询订单API]接口确认订单状态。
完整流程:
简单理解:
-
获取openId -> 下单 –> 调用小程序下单接口 -> 下单成功,返回预支付回话id
-
调起支付(使用预支付回话id) -> 支付成功
准备工作(需要准备的数据):
-
注册微信小程序账户、开通微信支付商户号、绑定小程序与商户号
-
商户号(mchid):xxxx
-
配置APIv3密钥:xxx(32位),用于签名和回调数据解密
-
小程序AppID:wx123456
-
小程序秘钥 appSecret: xxxxxx ,用于获取OpenID
-
商户证书序列号:xxxxxxxxxxxxxxxxxx
-
微信平台序列号:xxxxxxxxxxxxxxxxxx
-
私钥文件:apiclient_key.pem
以上数据在【微信商户平台】 都可查看。
小程序下单:
调用地址: 【请求域名】https://api.mch.weixin.qq.com
【请求方式】 POST /v3/pay/transactions/jsapi 请求参数: Http头参数 Authorization: 签名认证生成认证信息
构造请求签名:
-
构造签名串
HTTP请求方法\n --- POST
URL\n -- /v3/pay/transactions/jsapi 【/v3/refund/domestic/refunds】
请求时间戳\n -- 定义一个
请求随机串\n -- 调用随机函数生成
请求报文主体\n -- request
注意:当请求报文主体是一个空串时,只需要附加一个\n即可,例如: GET\n
/v3/certificates\n
1554208460\n
593BEC0C930BF1AFEB40B4A08C8FB242\n
\n
计算签名值
绝大多数编程语言提供的签名函数支持对签名数据进行签名。强烈建议商户调用该类函数,使用商户私钥对待签名串进行SHA256 with RSA签名,并对签名结果进行Base64编码得到签名值。
可用校验工具校验签名值是否正确;
设置 HTTP头
Authorization: 认证类型 签名信息
认证类型:WECHATPAY2-SHA256-RSA2048
签名信息: * 发起请求的商户(包括直连商户、服务商或渠道商)的商户号mchid
* 商户API证书序列号serial_no,用于声明所使用的证书
* 请求随机串nonce_str,和你上面构造签名串的随机串要保持一致
* 时间戳timestamp,和你上面构造签名串的时间戳要保持一致
* 签名值signature,上面算出来的签名值
注意:上述5项签名信息,无顺序要求;
示例:
Authorization:WECHATPAY2-SHA256-RSA2048 mchid="1900007291",nonce_str="593BEC0C930BF1AFEB40B4A08C8FB242",signature="gEuexJ547PHFV77TQ6eiE4tphVYfWfUe1Wc2dBmVnoMYU2rl/M4zhw+b3vBhuMw6AC7pteNkryLA7UWU2h+umo0OdSuuLm1++O3NckQPCSfm6dypsjn4GYm84KMqXWFrhFmyxEwIdEJDr3w1UYfxOcu55OQupfLkrt/ZzuOspnliJFrPzGQFUk7lGqMMtpz3EfbDUNxnVsHblORg3hVmuYNmbGWnS2ovU30Y2Q+iKFDxzkaXBk8LTy6HzvxizRo6Q+J4SVM7O0hKXfgo1QdI68kpzNULb3EVBXlhTyPUzhkHzzLxECL1qHl3HH2hEv8++C+4wBlsagF3j/O6PABojA==",timestamp="1554208460",serial_no="408B07E79B8269FEC3D5D3E6AB8ED163A6A380DB"
Accept: application/json Content-Type: application/json
var request = new { mchid = "商户号", appid = "小程序AppID", description = "订单描述", out_trade_no = orderNo, notify_url = "支付回调地址", amount = new { total = (int)(amount * 100) }, // 单位:分 payer = new { openid = openId } };
返回示例: {
"prepay_id" : "wx201410272009395522657a690389285100"
}
获取openID
wx.login({ success: res => { if (res.code) { console.log(res.code) uni.$ajax.post({ url:'api/WxPay/GetOpenId', data: { code:res.code }, success:(res =>{ // 检查 res.data 是否已经是对象 let data = res.data; if (typeof res.data === 'string') { data = JSON.parse(res.data); } console.log("openId:" + data.openid) this.openId = data.openid; // 放入缓存 uni.setStorageSync('xxxOpenId', this.openId); }) }); } } })
getOpenID(): https://api.weixin.qq.com/sns/jscode2session?appid={AppId}&secret={appSecret}&js_code={code}&grant_type=authorization_code
微信调起支付:
调用wx.requestPayment(OBJECT)发起微信支付
参数:
-
Timestamp:时间戳
-
NonceStr 随机字符串: 不长于32位
-
Package : 【预支付交易回话标识】: prepay_id=***
-
SignType: 默认为 RSA,仅支持RSA
-
PaySign: 【签名值】使用字段appId、timeStamp、nonceStr、package计算得出的签名
构造签名串:
小程序appID\n
时间戳\n
随机字符串\n
prepay_id\n
计算签名值: 绝大多数编程语言提供的签名函数支持对签名数据进行签名。强烈建议商户调用该 类函数,使用商户私钥对待签名串进行SHA256 with RSA签名,并对签名结果进行Base64编码得到签名值
回调结果
回调类型 | errMsg | 说明 |
---|---|---|
Success | requestPayment:ok | 调用支付成功 |
Fail | requestPayment:fail cancel | 用户取消支付 |
fail | requestPayment:fail (detail message) | 调用支付失败,其中detail message 为后台返回的详细失败原因 |
退款申请:
与小程序下单相似度极高,小程序下单写好,直接复制修改即可,很多东西都可以共用:比如:生成随机字符串、解密私钥等等。 【详见微信支付官方文档:小程序下单_小程序支付|微信支付商户文档中心】 微信官方文档还提供了很多的接口:例如:微信支付订单号查询订单、商户订单号查询订单、关闭订单、支付成功回调通知等等。
注意:
-
请求的时间戳相差不能超过5分钟;
-
微信支付的金额单位为:分,需要进行处理;
-
下单的notifyUrl:
-
商户侧对微信支付回调IP有防火墙策略限制的,需要对微信回调IP段开通白名单,否则会导致收不到回调(微信支付回调被商户防火墙拦截)
-
notify_url需要填写商户自己系统的真实地址,不能填写接口文档或demo上的示例地址。
-
notify_url必须是以https://或http://开头的完整全路径地址,并且确保URL中的域名和IP是外网可以访问的,不能填写localhost、127.0.0.1、192.168.x.x等本地或内网IP。
-
notify_url不能携带参数。
-
-
需要使用微信开发者工具进行调试运行(运行到小程序模拟器 – 微信开发者工具),测试支付时,点击真机调试即可。