在H5端实现调起微信APP支付需要通过一系列步骤,包括配置微信支付、前端调用微信支付接口、生成支付订单、调用支付接口等。下面是详细的步骤和代码示例:
1. 配置微信支付
首先需要在微信支付商户平台上进行配置,获取商户号(MchID)和API密钥(API Key),并且确保已开通支付功能。
2. 前端代码示例
前端代码主要是生成支付订单并调用微信支付接口。这里假设你使用的是Vue.js框架,其他框架类似。
HTML和JavaScript代码:
<!DOCTYPE html> <html> <head> <title>微信支付</title> <script src="https://res2.wx.qq.com/open/js/jweixin-1.6.0.js"></script> </head> <body> <button id="payBtn">微信支付</button> <script> // 微信配置 wx.config({ debug: false, appId: 'yourAppId', // 必填,公众号的唯一标识 timestamp: 0, // 必填,生成签名的时间戳 nonceStr: '', // 必填,生成签名的随机串 signature: '', // 必填,签名 jsApiList: ['chooseWXPay'] // 必填,需要使用的JS接口列表 }); // 获取支付订单参数 function getPaymentParams() { return fetch('https://your-backend-api.com/getPaymentParams', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ orderId: 'yourOrderId' }) }) .then(response => response.json()); } // 调用微信支付 function invokeWeChatPay(params) { wx.chooseWXPay({ timestamp: params.timestamp, // 支付签名时间戳 nonceStr: params.nonceStr, // 支付签名随机串,不长于 32 位 package: params.package, // 统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=*** signType: params.signType, // 签名类型,默认为'SHA1',使用新版支付需传入'MD5' paySign: params.paySign, // 支付签名 success: function (res) { // 支付成功后的回调函数 alert('支付成功'); }, fail: function (res) { // 支付失败后的回调函数 alert('支付失败'); } }); } document.getElementById('payBtn').addEventListener('click', function() { getPaymentParams().then(params => { invokeWeChatPay(params); }); }); </script> </body> </html>
代码说明:
微信配置:使用wx.config方法配置微信JS SDK,包括appId、timestamp、nonceStr和signature等。
获取支付订单参数:通过调用后台接口获取支付订单参数,包括timestamp、nonceStr、package、signType和paySign。
调用微信支付:使用wx.chooseWXPay方法调起微信支付,传入支付订单参数。
3. 后端代码示例
后端代码负责生成支付订单并返回给前端。以下是Node.js的示例代码。
Node.js代码:
const express = require('express'); const bodyParser = require('body-parser'); const request = require('request'); const crypto = require('crypto'); const app = express(); app.use(bodyParser.json()); const appId = 'yourAppId'; const mchId = 'yourMchId'; const apiKey = 'yourApiKey'; // 生成支付订单参数 app.post('/getPaymentParams', (req, res) => { const orderId = req.body.orderId; // 统一下单接口 const unifiedOrderUrl = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; const nonceStr = crypto.randomBytes(16).toString('hex'); const timestamp = Math.floor(Date.now() / 1000).toString(); const body = '商品描述'; const outTradeNo = orderId; const totalFee = 1; // 订单金额,单位为分 const spbillCreateIp = req.ip; const notifyUrl = 'https://your-notify-url.com/pay/notify'; const tradeType = 'JSAPI'; const openId = 'yourOpenId'; // 用户的OpenID // 签名 const params = { appid: appId, mch_id: mchId, nonce_str: nonceStr, body, out_trade_no: outTradeNo, total_fee: totalFee, spbill_create_ip: spbillCreateIp, notify_url: notifyUrl, trade_type: tradeType, openid: openId }; const stringA = Object.keys(params).sort().map(key => `${key}=${params[key]}`).join('&'); const stringSignTemp = `${stringA}&key=${apiKey}`; const sign = crypto.createHash('md5').update(stringSignTemp).digest('hex').toUpperCase(); const formData = `<xml> <appid>${appId}</appid> <mch_id>${mchId}</mch_id> <nonce_str>${nonceStr}</nonce_str> <sign>${sign}</sign> <body>${body}</body> <out_trade_no>${outTradeNo}</out_trade_no> <total_fee>${totalFee}</total_fee> <spbill_create_ip>${spbillCreateIp}</spbill_create_ip> <notify_url>${notifyUrl}</notify_url> <trade_type>${tradeType}</trade_type> <openid>${openId}</openid> </xml>`; request({ url: unifiedOrderUrl, method: 'POST', body: formData }, (err, response, body) => { if (err) { res.status(500).send(err); } else { // 解析微信返回的XML数据 const prepayId = /<prepay_id><!\[CDATA\[(.*)\]\]><\/prepay_id>/.exec(body)[1]; const paySign = crypto.createHash('md5').update(`appId=${appId}&nonceStr=${nonceStr}&package=prepay_id=${prepayId}&signType=MD5&timeStamp=${timestamp}&key=${apiKey}`).digest('hex').toUpperCase(); res.json({ timestamp, nonceStr, package: `prepay_id=${prepayId}`, signType: 'MD5', paySign }); } }); }); app.listen(3000, () => { console.log('Server is running on port 3000'); });
代码说明:
生成支付订单参数:接收前端传来的订单ID,生成支付订单参数,包括nonceStr、timestamp、outTradeNo、totalFee、spbillCreateIp、notifyUrl、tradeType和openId。
签名:对支付参数进行签名,生成sign。
调用统一下单接口:向微信支付的统一下单接口发送请求,获取prepayId。
返回支付参数:将prepayId、timestamp、nonceStr、package、signType和paySign返回给前端。
4. 回调处理
支付成功后,微信会回调商户服务器的通知URL。商户服务器需要对通知进行处理,并更新订单状态。
Node.js回调处理示例:
const xmlParser = require('express-xml-bodyparser'); // 微信支付回调通知 app.post('/pay/notify', xmlParser({trim: false, explicitArray: false}), (req, res) => { const xml = req.body.xml; const params = { appid: xml.appid, mch_id: xml.mch_id, nonce_str: xml.nonce_str, result_code: xml.result_code, openid: xml.openid, total_fee: xml.total_fee, out_trade_no: xml.out_trade_no }; const stringA = Object.keys(params).sort().map(key => `${key}=${params[key]}`).join('&'); const stringSignTemp = `${stringA}&key=${apiKey}`; const sign = crypto.createHash('md5').update(stringSignTemp).digest('hex').toUpperCase(); if (sign === xml.sign) { // 验签成功,处理业务逻辑 if (xml.result_code === 'SUCCESS') { // 支付成功,更新订单状态 // TODO: 更新数据库订单状态 res.send('<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'); } else { res.send('<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[支付失败]]></return_msg></xml>');