## 小程序支付接入前准备 https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_1.shtml ## v3支付官网接口规则 https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay-1.shtml > 关键字使用**JSON**作为数据交互的格式,不再使用XML,**SHA256-RSA**加密,只能使用HTTPS访问 ## 证书密钥使用说明 https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay3_0.shtml > 商户API私钥,APIv3密钥 ## 准备好所需资料,弄懂接口规则,Node.js 签名生成 ``` const crypto = require('crypto') const fs = require('fs') const stringRandom = require('string-random') const moment = require('moment') const x509_1 = require('@fidm/x509') // 支付签名拼接 getSignature(method, url, timestamp, nonce_str, body) { let str = method + '\n' + url + '\n' + timestamp + '\n' + nonce_str + '\n' if (body && body instanceof Object) body = JSON.stringify(body) if (body) str = str + body + '\n' if (method === 'GET') str = str + '\n' return this.sha256WithRsa(str) }, // SHA256-RSA加密后转base64 sha256WithRsa(data) { const privateKey = fs.readFileSync(`public/apiclient_key.pem`) if (!privateKey) throw '缺少私钥' return crypto.createSign('RSA-SHA256').update(data).sign(privateKey, 'base64') }, // 获取序列号 getSN() { const publicKey = fs.readFileSync(`public/apiclient_cert.pem`) if (!publicKey) throw '缺少公钥' const certificate = x509_1.Certificate.fromPEM(publicKey) return certificate.serialNumber }, // 发起请求 支付数据 async WechatPayPost() { const { appId, mchId } = this.app.config.wechatInfo // 小程序AppId和商户Id const schema = 'WECHATPAY2-SHA256-RSA2048' // 认证信息 const timestamp = moment().unix() // 时间戳 const nonce_str = stringRandom(16) // 随机数 const notifyUrl = 'https://www.googleapis.com/' // 回调地址 const serial_no = this.getSN() // 获取证书序号 // 请求体Body const params = { appid: appId, // 应用ID string[1,32] mchid: mchId, // 直连商户号 string[1,32] description: '小程序支付调试', // 商品描述 string[1,127] out_trade_no: nonce_str, // 商户订单号[6,32] 只能是数字、大小写字母_-*,并且同一个商户号下唯一 attach: '自定义数据', // 附加数据 string[1,128] 在查询API和支付通知中原样返回,可作为自定义参数使用 notify_url: notifyUrl, // 通知地址https string[1,256] amount: { // 订单金额 单位分 total: 1 }, payer: { // 支付者信息 open_id openid: '微信open_id' // string[1,128] } } // 获取签名 const sign = this.getSignature('POST', '/v3/pay/transactions/jsapi', timestamp, nonce_str, params) // 获取prepay_id 特别注意拼接签名信息后是双引号 const authorization = `${schema} mchid="${mchId}",nonce_str="${nonce_str}",timestamp="${timestamp}",serial_no="${serial_no}",signature="${sign}"` const res = await wechatAPI.GetPrePayId( params, authorization ) // 小程序支付需要字段 let preData = { status: res.status, appId: appId, timeStamp: moment().unix(), nonceStr: stringRandom(16), package: `prepay_id=${res.prepay_id}`, signType: 'RSA', paySign: '' } // 拼接所需字段 const str = [preData.appId, preData.timeStamp, preData.nonceStr, preData.package, ''].join('\n') preData.paySign = this.sha256WithRsa(str) return preData } ``` ### API请求 ``` const axios = require('axios') const GetPrePayId = ('https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi', data, authorization) => { return new Promise((resolve, reject) => { axios .post(url, data, { headers: { Authorization: authorization } }) .then((res) => { resolve({ status: res.status, ...res.body }) }) .catch((err) => { const fail = JSON.parse(JSON.stringify(err)) reject(fail) }) }) } ```