微信作为中国乃至全球最大的社交媒体平台之一,拥有数亿活跃用户,其中大部分用户习惯使用微信支付进行日常消费。小程序支付直接对接微信支付系统,使得商家能够触达这一庞大的潜在客户群体。借助微信的高用户粘性和高频使用特性,小程序支付能够有效扩大商家的服务覆盖范围,吸引和留住更多消费者。
以下是实现微信小程序支付API全流程:
一、用户下单
前端(小程序端)收集用户下单信息(如商品信息、总价、用户OpenID等)
- 订单ID(order_id)
- 商品总价(total_amount)
- 商品描述(body)
- 用户OpenID(openid,已通过wx.login获取并存储)
通过HTTP请求发送到后端:
// 小程序前端
const orderData = {
order_id: 'ORDER_12345',
total_amount: 99.99,
body: '商品A × 1',
openid: 'o1234567890'
};
wx.request({
url: 'https://your-backend.com/api/create_order',
method: 'POST',
data: orderData,
header: { 'content-type': 'application/json' },
success(res) {
const serverResponse = res.data;
if (serverResponse.success) {
// 后端返回预支付参数,继续支付流程
handlePrepayParams(serverResponse.prepayParams);
} else {
// 处理创建订单失败的情况
console.error('创建订单失败', serverResponse.errorMessage);
}
},
fail(err) {
console.error('请求创建订单接口失败', err);
}
});
二、后端生成预支付订单(Node.js)
后端接收到前端请求后,商户在小程序中先调用统一下单接口在微信支付服务后台生成预支付交易单,返回正确的预支参数后调起支付。
请求参数(官方参数):
// Node.js后端
const WechatPay = require('wechat-pay');
const wechatPayInstance = new WechatPay({
appid: process.env.WECHAT_APPID,
mchid: process.env.WECHAT_MCHID,
apiKey: process.env.WECHAT_API_KEY,
pfx: fs.readFileSync(process.env.WECHAT_CERT_PATH),
});
app.post('/api/create_order', async (req, res) => {
try {
const { order_id, total_amount, body, openid } = req.body;
const unifiedOrderResult = await wechatPayInstance.unifiedOrder({
out_trade_no: order_id,
body,
total_fee: Math.round(total_amount * 100), // 转换为分
spbill_create_ip: req.ip, // 用户IP地址
notify_url: `${process.env.BASE_URL}/api/payment/notify`, // 回调URL
trade_type: 'JSAPI',
openid,
});
if (unifiedOrderResult.return_code === 'SUCCESS' && unifiedOrderResult.result_code === 'SUCCESS') {
const prepayParams = {
appId: unifiedOrderResult.appid,
timeStamp: Math.floor(Date.now() / 1000),
nonceStr: generateNonceStr(),
package: `prepay_id=${unifiedOrderResult.prepay_id}`,
signType: 'RSA', // 或者使用HMAC-SHA256
paySign: await wechatPayInstance.getPaySign(prepayParams),
};
res.json({ success: true, prepayParams });
} else {
res.json({ success: false, errorMessage: '生成预支付订单失败' });
}
} catch (error) {
console.error('创建订单错误:', error);
res.status(500).json({ success: false, errorMessage: '服务器内部错误' });
}
});
三、前端调用支付接口
前端接收到后端返回的预支付参数后,调用wx.requestPayment()
方法启动微信支付。wx.requestPayment参数(官方参数):
属性 | 类型 | 必填 | 说明 |
---|---|---|---|
timeStamp | string | 是 | 时间戳,从 1970 年 1 月 1 日 00:00:00 至今的秒数,即当前的时间 |
nonceStr | string | 是 | 随机字符串,长度为32个字符以下 |
package | string | 是 | 统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=*** |
signType | string | 否 | 签名算法,应与后台下单时的值一致;默认MD5(HMAC-SHA256、RSA) |
paySign | string | 是 | 签名,具体见微信支付文档 |
success | function | 否 | 接口调用成功的回调函数 |
fail | function | 否 | 接口调用失败的回调函数 |
complete | function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
// 小程序前端
function handlePrepayParams(prepayParams) {
wx.requestPayment({
...prepayParams,
success(res) {
console.log('支付成功');
// 更新UI,提示用户支付成功,可能跳转至订单详情页或感谢页
navigateToOrderSuccessPage();
},
fail(err) {
console.error('支付失败', err);
// 处理支付失败情况,提示用户并提供重新支付选项
},
complete() {
// 支付流程结束后的统一处理,如关闭加载提示等
}
});
}
四、用户完成支付
用户在弹出的微信支付界面中确认支付信息,输入支付密码或使用其他验证方式完成支付。
五、微信通知后端支付结果
支付成功后,微信支付平台通过HTTPS POST请求向后端指定的notify_url
(官方参数):发送支付结果通知:
{
"appid": "your_app_id",
"bank_type": "CMB_CREDIT",
"cash_fee": "999",
"fee_type": "CNY",
"is_subscribe": "Y",
"mch_id": "your_merchant_id",
"nonce_str": "5d2b6c2aebae49e99f16cdd221ccac1c",
"openid": "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o",
"out_trade_no": "your_order_id",
"result_code": "SUCCESS",
"return_code": "SUCCESS",
"sign": "FA1D17E17B3236B9D25C31FAC9F31F8E",
"time_end": "20140.jpg",
"total_fee": "999",
"trade_type": "JSAPI",
"transaction_id": "1008450740201411110005820873"
}
注:notify_url地址在第二步统一下单接口里配置。
六、后端处理支付结果
后端接收到通知后,使用微信支付SDK验证签名和数据完整性,确认支付成功后更新订单状态为“已支付”:
// Node.js后端
app.post('/api/payment/notify', async (req, res) => {
try {
const notificationBody = req.body;
const isValidSignature = await wechatPayInstance.verifyPaymentNotification(notificationBody);
if (isValidSignature) {
if (notificationBody.return_code === 'SUCCESS' && notificationBody.result_code === 'SUCCESS') {
// 更新订单状态为已支付
await updateOrderStatus(notificationBody.out_trade_no, 'PAID');
res.status(200).send('OK'); // 必须返回200,否则微信会重试通知
} else {
console.warn('支付通知:非成功状态', notificationBody);
res.status(200).send('OK'); // 即使非成功状态,也应返回200以停止重试
}
} else {
console.error('支付通知签名验证失败');
res.status(400).send('Invalid signature');
}
} catch (error) {
console.error('处理支付通知错误:', error);
res.status(500).send('Server error');
}
});
此接口服务为notify_url配置的自定义服务端接口。
七、后端通知前端支付结果(可选)
如果需要实时更新前端UI,后端可以通过WebSocket、长轮询、服务器推送(如信鸽、极光推送等)自定义服务端接口的数据结果或其他合适的方式,将支付成功结果通知给前端。前端接收到通知后,更新UI显示支付成功状态,可能跳转至订单详情页或感谢页。
// Node.js后端(使用WebSocket示例)
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', ws => {
ws.on('message', message => {
// 处理客户端消息
});
ws.send(JSON.stringify({ type: 'payment_success', order_id: 'ORDER_12345' }));
});
// 小程序前端
const socket = new WebSocket('wss://your-backend.com/ws');
socket.addEventListener('message', function(event) {
const message = JSON.parse(event.data);
if (message.type === 'payment_success') {
console.log('支付成功(WebSocket通知)');
navigateToOrderSuccessPage();
}
});
八、退款
微信支付开发退款API(官方参数)是指通过编程接口实现的商户端主动发起的退款操作。以下是使用微信支付API进行退款的详细示例,以帮助开发者理解并实现退款功能:
前置准备
-
商户账号:已注册并认证的微信支付商户账号,拥有有效的商户ID(
mch_id
)和API密钥(api_key
)。 -
证书:如需使用API退款,需下载并安装商户API证书(
.p12
或.pem
文件),用于加密退款请求。 -
支付订单:要退款的交易必须已完成,且未超出退款期限(一般为交易后的90天内)。
退款请求示例
使用微信支付API进行退款时,通常需要向微信支付服务器发送一个退款请求,包含以下信息:
- 商户订单号(
out_trade_no
):商户系统内部的订单号,与微信支付订单号(transaction_id
)对应。 - 微信支付订单号(
transaction_id
):微信支付生成的订单号,与商户订单号对应。 - 退款单号(
out_refund_no
):商户系统内部的退款单号,用于区分不同的退款请求。 - 退款金额(
refund_fee
):退款金额,单位为分。 - 货币类型(
refund_fee_type
):货币类型,默认为CNY。 - 退款原因(
refund_desc
):退款原因说明,供商户后台和用户查询。 - 签名信息:根据微信支付API要求,计算请求参数的签名。
以下是一个使用HTTP POST方式调用微信退款API的示例(使用Python示例代码,实际应用中请根据所使用的编程语言和微信支付SDK进行调整):
const request = require('request');
const xml2js = require('xml2js');
const fs = require('fs');
// 商户配置信息
const MCH_ID = 'your_merchant_id';
const API_KEY = 'your_api_key';
const API_CERT_PATH = 'path/to/your/apiclient_cert.p12'; // API证书路径
const API_CERT_PASSWORD = 'your_certificate_password'; // API证书密码(如有)
// 退款请求参数
const outTradeNo = 'YOUR_OUT_TRADE_NO';
const transactionId = 'YOUR_TRANSACTION_ID';
const outRefundNo = `refund_${Date.now().toString(36)}`; // 生成退款单号
const refundFee = 100; // 退款金额为1元
const refundDesc = '商品质量问题退款';
function getNonceStr() {
return Math.random().toString(36).substr(2, 32);
}
function generateSign(params) {
const signParams = Object.entries(params)
.filter(([key]) => key !== 'sign')
.sort((a, b) => a[0].localeCompare(b[0]))
.map(([key, value]) => `${key}=${value}`)
.join('&');
const stringToSign = `${signParams}&key=${API_KEY}`;
const sign = md5(stringToSign).toUpperCase();
return sign;
}
function buildRefundRequestXML() {
const nonceStr = getNonceStr();
const sign = generateSign({
appid: MCH_ID,
mch_id: MCH_ID,
nonce_str: nonceStr,
out_trade_no: outTradeNo,
transaction_id: transactionId,
out_refund_no: outRefundNo,
total_fee: 100, // 原订单总金额(单位分)
refund_fee: refundFee,
refund_desc: refundDesc,
});
const refundRequestData = {
appid: MCH_ID,
mch_id: MCH_ID,
nonce_str: nonceStr,
out_trade_no: outTradeNo,
transaction_id: transactionId,
out_refund_no: outRefundNo,
total_fee: 100,
refund_fee: refundFee,
refund_desc: refundDesc,
sign: sign,
};
return xml2js.Builder().buildObject(refundRequestData);
}
function sendRefundRequest(refundRequestXML) {
const options = {
url: 'https://api.mch.weixin.qq.com/secapi/pay/refund',
method: 'POST',
body: refundRequestXML,
headers: {
'Content-Type': 'text/xml',
},
agentOptions: {
pfx: fs.readFileSync(API_CERT_PATH),
passphrase: API_CERT_PASSWORD, // 如果有密码的话
},
};
request(options, (error, response, body) => {
if (error) {
console.error('Error sending refund request:', error);
return;
}
parseRefundResponse(body);
});
}
function parseRefundResponse(xmlBody) {
xml2js.parseString(xmlBody, (err, result) => {
if (err) {
console.error('Error parsing refund response:', err);
return;
}
const refundResponse = result.xml;
if (
refundResponse.return_code === 'SUCCESS' &&
refundResponse.result_code === 'SUCCESS'
) {
console.log('退款成功');
console.log('退款单号:', refundResponse.refund_id);
console.log('退款金额:', refundResponse.refund_fee);
} else {
console.log('退款失败');
console.log('错误码:', refundResponse.err_code);
console.log('错误描述:', refundResponse.err_code_des);
}
});
}
const refundRequestXML = buildRefundRequestXML();
sendRefundRequest(refundRequestXML);
这个示例涵盖了以下关键步骤:
-
商户配置:设置商户ID、API密钥、API证书路径和证书密码(如有)。
-
退款请求参数:定义商户订单号、微信支付订单号、退款单号、退款金额、退款原因等参数。
-
构建退款请求XML:创建XML结构,填充退款请求参数,并计算签名。
-
发送退款请求:使用
request
库发送POST请求至微信退款API,同时指定证书进行SSL连接。 -
解析退款响应:接收并解析微信返回的XML响应,检查返回码和结果码,输出退款结果。
请确保替换示例中的占位符(如your_merchant_id
、your_api_key
等)为实际的商户信息,并根据您的环境调整API证书路径和密码(如有)。运行上述代码后,根据控制台输出判断退款是否成功,并根据需要进行后续操作,如保存退款记录、通知用户等。
退款响应处理
微信支付服务器接收到退款请求后,会进行处理并返回一个响应。响应中包含退款结果及退款详情。开发者需要检查响应中的返回码和结果码,判断退款是否成功。常见的响应字段包括:
- return_code:返回状态码,
SUCCESS
表示请求接收成功,FAIL
表示请求接收失败。 - result_code:业务结果,
SUCCESS
表示退款成功,FAIL
表示退款失败。 - err_code:错误码,退款失败时提供具体错误原因。
- err_code_des:错误描述,对错误码的详细解释。
- refund_id:微信支付退款单号,用于查询退款状态。
- refund_fee:实际退款金额,单位为分。
- total_fee:原订单总金额,单位为分。
- cash_fee:原订单现金支付金额,单位为分。
后续操作
-
保存退款记录:根据退款响应结果,保存退款记录至商户系统,包括退款单号、退款金额、退款状态等信息。
-
通知用户:退款成功后,可向用户发送退款成功的通知,如短信、站内消息等。
-
退款状态查询:如需了解退款的后续状态(如退款是否到账、退款是否被撤销等),可通过微信支付退款查询接口进行查询。
注意事项
- 退款次数限制:同一笔交易可多次退款,但累计退款金额不能超过原订单金额。
- 退款时效:建议在交易完成后的90天内发起退款,超过此期限可能无法退款。
- 退款资金来源:退款资金通常优先从商户可用余额中扣除,不足部分从商户绑定的结算银行卡扣款。
- 签名计算:确保在构造退款请求时正确计算签名,使用正确的API密钥,并遵循微信支付签名规则。
- 证书管理:妥善保管API证书,确保在请求时正确使用证书进行SSL连接。
以上就是一个使用微信支付开发API进行退款的详细示例。开发者需根据实际业务需求和微信支付接口文档进行适当的调整和优化。
九、异常处理与回退
在整个支付过程中,应充分考虑异常情况的处理,如网络中断、支付超时、用户取消支付等。对于支付失败或用户取消支付的情况,应在前端提供重新支付的选项,并确保后端订单状态与实际情况一致。
十、uniapp支付配置
unipay为uniCloud开发者提供了简单、易用、统一的支付能力封装。让开发者无需研究支付宝、微信等支付平台的后端开发、无需为它们编写不同代码,拿来即用,屏蔽差异。
const path = require('path')
module.exports = {
// 微信小程序端对应的微信支付及登录配置配置
wxConfigMp: {
appId: '',
secret: '',
mchId: '',
key: '',
},
// App端对应的微信支付配置
wxConfigApp: {
appId: '',
mchId: '',
key: '',
},
// 微信PC网站支付
wxConfigH5: {
appId: '',
mchId: '',
key: ',
},
// 支付宝小程序端对应的支付宝支付及登录配置
aliConfigMp: {
mchId: "",
appId: "",
alipayPublicKey: "",
privateKey: "",
},
// App端对应的支付宝支付配置
aliConfigApp: {
mchId: "",
appId: "",
alipayPublicKey: "",
privateKey: "",
}
}
注意:
微信支付前提条件:
- 您已经注册并拥有了一个微信小程序账号。
- 小程序已完成微信认证(企业类型小程序需要,个人主体小程序可能无法开通微信支付)。
- 您有合法的营业执照及相关资质(适用于企业主体)。
其他:
微信支付官方文档:https://pay.weixin.qq.com/wiki/doc/api/index.html
微信商户平台:https://pay.weixin.qq.com