1、调用下单接口
/**
* 微信app支付
*/
async wxAppPay(ctx, params, mchKey) {
const orderSign = ctx.service.wx.sign(params, mchKey);
let formData = `<xml>
<appid>${params.appid}</appid>
<mch_id>${params.mch_id}</mch_id>
<nonce_str>${params.nonce_str}</nonce_str>
<sign>${orderSign}</sign>
<sign_type>${params.sign_type}</sign_type>
<body>${params.body}</body>
<out_trade_no>${params.out_trade_no}</out_trade_no>
<total_fee>${params.total_fee}</total_fee>
<spbill_create_ip>${params.spbill_create_ip}</spbill_create_ip>
<notify_url>${params.notify_url}</notify_url>
<trade_type>APP</trade_type>
<profit_sharing>${params.profit_sharing}</profit_sharing>
</xml>`
// 调用统一下单接口(接口没说明,但必须为post请求)
const res = await ctx.curl(
"https://api.mch.weixin.qq.com/pay/unifiedorder",
{
method: "post",
data: formData,
}
)
const datastring = res.data.toString()
return new Promise((resolve, reject) => xml2js.parseString(datastring, async (err, result) => {
if (err) {
reject(err)
} else {
resolve(result)
}
}))
}
2、得到prepayid之后再次加密将结果返回给App
function EncryptSign(result) {
let prepay_id = result.xml.prepay_id[0];
const resdata = {
appid: params.appid, // 商户 id
partnerid: params.mch_id,
prepayid: prepay_id,
package: "Sign",
noncestr: result.xml.nonce_str[0],
timestamp: Math.floor(Date.now() / 1000).toString()
}
const paySign = ctx.service.wx.sign(resdata, mchKey)
resdata.sign = paySign
return resdata
}
正常走到这一步就ok了,顺利的话客户端就能拉起微信进行支付操作。
3、验证签名失败错误
-
检查一下第二步的
appid partnerid prepayid package noncestr timestamp
是否为小写,没有的话改成小写不要写成驼峰 -
官方文档上第二步的
package
参数为”Sign=WXPay“但是通过微信支付接口签名校验工具测试的时候发现package="Sign",所以将此参数改为Sign
-
检查一下
timestamp
是否是以秒为单位的。长度为10
4、附:签名算法,微信支付接口签名校验工具地址
// 签名
sign(data, mchKey, signType = 'MD5') {
const keys = [];
for (const key in data) {
if (data[key] !== undefined) {
keys.push(key);
}
}
// 字典排序=>key=value
const stringA = keys
.sort()
.map(key => `${key}=${decodeURIComponent(data[key])}`)
.join('&');
// 拼接商户key
const stringSignTemp = stringA + '&key=' + mchKey;
// 加密
let hash;
if (signType === 'MD5') {
hash = crypto.createHash('md5').update(stringSignTemp);
} else {
hash = crypto.createHmac('sha256', mchKey).update(stringSignTemp, 'utf8');
}
const paySign = hash.digest('hex').toUpperCase();
return paySign;
}