场景
本人正在对接微信小程序的微信支付,使用的是 PHP + EasyWechat 这样的技术栈,本想着一下子就可以搞定了,结果踩了个大坑,就是当我通过后端向微信服务器发起支付请求后,直接将请求结果返回给小程序。然后以为微信服务器返回的 sign 就是传给小程序支付的 paySign 。其实不是!
真正的 paySign 是还需要在微信服务器返回消息后拿支付密钥在后端自己算出来,在发给小程序发起支付的。
解决代码
下面给出我的支付代码,防止大家踩坑,大家可以自己复制去用
后端
$order = [
'body' => '天猫超市-鸡蛋购买',
'out_trade_no' => 订单号,
'openid' => 这里填下单用户的openid,
'total_fee' => 100, // 如果你的价钱是小数记得要 * 100
'trade_type' => 'JSAPI',
'notify_url' => 回调地址,
'sign_type' => 'MD5',
];
//self::wechatPayInstance() 就是 EasyWechat 这个包的 Factory::payment($config),稍微封装了一下
$res = self::wechatPayInstance()->order->unify($order);
if ($res['return_code'] != 'SUCCESS'){
throw new Exception('订单已创建,但发起微信支付失败');
}
$appId = $res['appid'];
$nonceStr = $res['nonce_str'];
$prepay_id = $res['prepay_id'];
$timeStamp = time();
$key = config('wxpay.key');
$paySign = md5("appId=$appId&nonceStr=$nonceStr&package=prepay_id=$prepay_id&signType=MD5&timeStamp=$timeStamp&key=$key"); // 这个地方就是我所说的二次签名!
return [ // 返回给小程序使用
'nonceStr' => $nonceStr,
'prepay_id' => $prepay_id,
'timeStamp' => strval($timeStamp), // 小程序支付的timeStamp参数,必须使用这个 timeStamp,因为他已经被计算到了paySign中
'paySign' => $paySign,
'signType' => 'MD5'
];
前端
// pay_info 就是刚才后端返回的那个数组
const config = {
timeStamp: pay_info.timeStamp,
nonceStr : pay_info.nonceStr,
package: `prepay_id=${pay_info.prepay_id}`,
signType: pay_info.signType,
paySign: pay_info.paySign,
}
wx.requestPayment({
...config,
success() {
console.log('微信支付成功')
resolve()
},
fail(e) {
console.log('微信支付失败', e)
reject()
}
})
})
总结
首先,出现这样的问题是在所难免的,但是我认为我有以下几点做的好,也有几点做的不好。
做的比较好的
- 首先出现问题后第一时间比对参数,检查代码是否正确做的很好。
- 在尝试很多种方法后,能够不偷懒,重新将以前的项目配置跑起来,进行对比最终找到问题是一个很好的点。以后如果也有这样的问题,最好也要用这种方式解决。
做的不好的
- 在检查完参数后没有及时仔细的阅读原有官方文档,导致没有及时发现问题,浪费了大量时间在百度和谷歌上。
- 出现问题一直犟着不肯休息,对身体不好,以后一定要注意!休息 5 分钟都是好的。