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