微信JSAPI支付(境外)踩坑记录
日期: 2019-10-28 浏览量: 10527
这两周在对接微信支付(境外版),感慨万千,生活不容易,且行且珍惜。 (默默的诅咒下微信,别问我为啥)
一. 准备工作
1. 申请境外商户 (具体怎么申请,请问微信客服)
2. 注册微信公众号 (怎么注册,自行百度)
3. 商户绑定公众号 (⚠️注意:如果你的商户主体和微信公众号主体不是一个,自己是办法绑定的,请联系微信客服,或者你的Bd经理 )
4. 商户绑定公众号成功后,请在商户平台生成我们需要用到的API证书及商户keys(APIv3 secret)如下图:
在生成API证书时,我们要使用微信生成工具,在生成后,会包含三个在证书文件(.pem),请妥善保管。 apiclient_key.pem 是密钥文件我们下面会用到。
二. 微信公众号授权(获取openid)
1. 微信公众号授权请看官方文档(这里没有坑)微信传送门 https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
三. 支付下单
1. 文档说明 (境外支付文档需要看v3版本,下载地址链接: https://pan.baidu.com/s/17flGOD0CYizsU0T3EoBV4g 提取码: 366a)自测只有这个版本是对的,官网上的都是坑。
2. 统一下单(详情请看文档,这里直接上代码 node.js)
let unifiedUrl = 'https://apihk.mch.weixin.qq.com/hk/v3/transactions/jsapi'; // 微信统一下单接口 let productName = '小棉袄一件'; //商品名称 // 请求参数 let pay_parameter = { 'mchid': '1052***49', //商户号 'appid': 'wx459f9b30****b725', // appid 'description': productName, // 描述 'notify_url': 'https://***.fangzhenqi.xin/api**/wx/pay-callback', //回调通知地址 'out_trade_no': '123*****32f', //订单号 'trade_type': 'JSAPI', // 支付方式固定的 'merchant_category_code': '5977', // 商业编号 具体看文档 'payer': { openid: 'openid' // 用户的openid }, 'amount': { total: 10, // 支付金额 整数 currency: 'HKD' // 币种 } }; // 时间 let time = Math.round(new Date().getTime() / 1000).toString(); // 签名字符串 let randomStr = Math.random().toString(36).substr(2, 15); // 组成签名字符串 let str = `POST\n/hk/v3/transactions/jsapi\n${time}\n${randomStr}\n${JSON.stringify(pay_parameter)}\n`; // 密钥是在生成api证书时下载的密钥文件 let PrivateKey = String(fs.readFileSync('私钥证书路径/apiclient_key.pem', 'utf-8')); // rsa签名 安装依赖包 node-rsa let key = new NodeRsa(PrivateKey, { signingScheme: 'sha256' }); let sign = key.sign(str, "base64", "utf8"); // 请求头信息 serial_no 证书编号 在商户平台 - 证书 可以查看 let authorization = `WECHATPAY2-SHA256-RSA2048 mchid="105****49",nonce_str="${randomStr}",signature="${sign}",timestamp="${time}",serial_no="25C835B74B3C********5341E7"`; const result = await new Promise((reslove, reject) => { request({ url: unifiedUrl, method: "POST", json: true, headers: { "authorization": authorization, "User-Agent": '127.0.0.1', 'Content-Type': 'application/json', }, body: pay_parameter }, function (error, response, body) { if (!error) { reslove(body); } else { reject(error); } }); }) // 下单成功后 前端唤醒支付 数据做签名处理 if (!result.prepay_id) { return false }; let timeStamp = Math.round(new Date().getTime() / 1000).toString(); let nonceStr = Math.random().toString(36).substr(2, 15); //做数据签名 str = `wx459f9*****5b725\n${timeStamp}\n${nonceStr}\nprepay_id=${result.prepay_id}\n`; let paySign = key.sign(str, "base64", "utf8"); //返回数据 前端拿此数据直接可唤醒微信支付 return { appId: 'wx45*******d5b725', timeStamp: timeStamp, nonceStr: nonceStr, package: `prepay_id=${result.prepay_id}`, signType: 'RSA', paySign: paySign }
3. 在微信内部前端唤醒支付方法
WeixinJSBridge.invoke('getBrandWCPayRequest', res.data, function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ) { alert('好像成功了'); } });
4. 回调解密
let key = `fqnp5********6166lbkw88`; // 解密key 上面提到的商户keys(APIv3 secret) let nonce = param.resource.nonce; // 加密使用的随机串 let associated_data = param.resource.associated_data; // 加密用的附加数据 let ciphertext = param.resource.ciphertext; // 加密体 base64 // 解密 ciphertext字符 AEAD_AES_256_GCM算法 ciphertext = Buffer.from(ciphertext, 'base64'); let authTag = ciphertext.slice(ciphertext.length - 16); let data = ciphertext.slice(0, ciphertext.length - 16); let decipher = crypto.createDecipheriv('aes-256-gcm', key, nonce); decipher.setAuthTag(authTag); decipher.setAAD(Buffer.from(param.resource.associated_data)); let decoded = decipher.update(data, null, 'utf8'); decipher.final(); let payData = JSON.parse(decoded); //解密后的数据 // 订单状态更新操作
人活着,其实就是一种心态,你若觉得快乐,幸福无处不在;你为自己悲鸣,世界必将灰暗。
阅读排行
最新文章
联系方式
- 邮箱:m18811126599@163.com
- QQ:896956692