在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>');