微信小程序jsapi支付的实现涉及多个步骤,主要包括前端请求订单信息、后端处理订单并返回支付参数、前端调用jsapi进行支付等。以下是一个基本的实现流程:
在小程序中,当用户触发支付行为时(例如点击购买按钮),前端会向后端发送请求,请求中包含订单的相关信息(如商品ID、数量、用户ID等)。
后端接收到前端的请求后,会进行订单处理,包括验证订单信息、生成订单号、调用微信支付API获取支付参数等。支付参数主要包括prepay_id
、package
、nonce_str
、timestamp
、sign
等。
获取支付参数的一般流程如下:
验证订单信息:首先,后端需要验证从前端接收到的订单信息的有效性,包括检查商品ID、数量、用户ID等是否合法。
生成订单:验证通过后,后端会根据订单信息生成订单,并保存到数据库中。这一步通常包括生成唯一的订单号、计算订单金额等。
调用微信支付API:生成订单后,后端需要调用微信支付的统一下单API来获取支付参数。这通常涉及以下步骤:
构建请求参数:根据微信支付的文档,构建包含必要信息的请求参数,如商户ID、API密钥、商品描述、订单金额、回调地址等。
发送请求:使用HTTP客户端(如Node.js中的axios
或request
库)向微信支付的API接口发送请求。
处理响应:接收微信支付的响应,并解析返回的数据。如果请求成功,响应中会包含prepay_id
等支付参数。
生成签名:根据微信支付的签名规则,使用商户的API密钥和其他支付参数生成签名。这个签名将在前端调用wx.requestPayment
时使用,以确保支付请求的安全性。
返回支付参数:将生成的签名和其他支付参数(如prepay_id
、nonce_str
、timestamp
等)返回给前端。
前端接收到后端返回的支付参数后,可以调用微信小程序的jsapi进行支付。具体步骤如下:
requestPayment
方法:使用小程序提供的wx.requestPayment
方法发起支付请求。该方法需要传入一个包含支付参数的对象。// 发送订单请求到后端
wx.request({
url: "后端接口地址",
data: {
orderId: "订单ID",
userId: "用户ID",
// 其他订单信息...
},
success: function (res) {
if (res.data.success) {
// 调用jsapi进行支付
wx.requestPayment({
timeStamp: res.data.timestamp,
nonceStr: res.data.nonce_str,
package: res.data.package,
signType: "MD5",
paySign: res.data.sign,
success: function (res) {
// 支付成功处理逻辑...
},
fail: function (res) {
// 支付失败处理逻辑...
}
});
} else {
// 请求订单失败处理逻辑...
}
}
});
const express = require("express");
const axios = require("axios");
const crypto = require("crypto");
const xml2js = require("xml2js"); // 用于解析XML响应
const app = express();
app.use(express.json());
// 假设你已经有了处理订单并返回订单信息的函数
const handleOrder = async (orderInfo) => {
// 在这里处理订单逻辑,如保存到数据库等
// 返回订单信息,包括订单号等
// 示例数据
return { orderId: "1234567890", orderAmount: 100 };
};
// 生成随机字符串
const generateNonceStr = () => {
return crypto.randomBytes(32).toString("hex");
};
// 生成签名
const generateSign = (params, apiKey) => {
// 排序参数
const keys = Object.keys(params).sort();
let stringA = "";
keys.forEach((key) => {
if (key !== "sign") {
stringA += `${key}=${params[key]}&`;
}
});
stringA += `key=${apiKey}`;
const sign = crypto.createHash("MD5").update(stringA, "utf8").digest("hex").toUpperCase();
return sign;
};
// 调用微信支付API获取支付参数
const getWechatPayParams = async (orderId, orderAmount) => {
const apiUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder"; // 微信支付统一下单API
const apiKey = "YOUR_API_KEY"; // 你的微信支付API密钥
const mchId = "YOUR_MCH_ID"; // 你的商户号
const notifyUrl = "YOUR_NOTIFY_URL"; // 你的支付结果通知回调地址
const params = {
appid: "YOUR_APP_ID", // 你的小程序AppID
mch_id: mchId,
nonce_str: generateNonceStr(),
body: "商品描述",
out_trade_no: orderId,
total_fee: orderAmount * 100, // 单位:分
spbill_create_ip: "用户IP", // 用户的IP,这个在实际使用时需要从请求中获取
notify_url: notifyUrl,
trade_type: "JSAPI",
};
params.sign = generateSign(params, apiKey);
try {
const response = await axios.post(apiUrl, new Buffer.from(xml2js.builder.buildObject(params)).toString("base64"), {
headers: {
"Content-Type": "application/xml",
},
});
const result = await xml2js.parseStringPromise(response.data);
if (result.xml && result.xml.return_code === "SUCCESS" && result.xml.result_code === "SUCCESS") {
const prepayId = result.xml.prepay_id[0];
const timeStamp = Math.round(new Date().getTime() / 1000).toString();
const nonceStr = generateNonceStr();
const packageStr = `prepay_id=${prepayId}`;
const paySign = generateSign({
appId: "YOUR_APP_ID",
timeStamp,
nonceStr,
package: packageStr,
}, apiKey);
return {
appId: "YOUR_APP_ID",
timeStamp,
nonceStr,
package: packageStr,
signType: "MD5",
paySign,
};
} else {
throw new Error("获取支付参数失败");
}
} catch (error) {
throw new Error("调用微信支付API失败");
}
};
// 示例路由:处理订单并返回支付参数
app.post("/api/createOrder", async (req, res) => {
try {
const orderInfo = req.body; // 假设从请求体中获取订单信息
const orderResult = await handleOrder(orderInfo);
const { orderId, orderAmount } = orderResult;
const wechatPayParams = await getWechatPayParams(orderId, orderAmount);
// 返回支付参数给前端
res.json({
status: "success",
message: "订单已创建,获取到支付参数",
data: wechatPayParams,
});
} catch (error) {
console.error("处理订单或获取支付参数时出错:", error);
res.status(500).json({
status: "error",
message: "处理订单或获取支付参数时出错",
error: error.message,
});
}
});
// 启动服务器
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
module.exports = app; // 如果需要的话,将app导出供其他模块使用
这个示例代码定义了一个Express服务器,它有一个/api/createOrder
的POST路由。当这个路由被调用时,它会处理订单信息,然后调用getWechatPayParams
函数来获取微信支付所需的参数。如果一切顺利,它会将这些参数作为JSON响应返回给前端。如果在这个过程中发生任何错误,它会捕获这些错误并以适当的HTTP状态码和错误消息响应。
请注意,代码中涉及到的API密钥、商户号、AppID、通知URL等都是需要替换为实际值的占位符。你需要确保这些值是从你的微信支付商户平台获取的,并且妥善保管好你的API密钥,不要将其硬编码在代码中或公开分享。
此外,getWechatPayParams
函数中的new Buffer.from(...)
是Node.js旧版本中的用法,在新版本中已经被弃用。建议使用Buffer.from(xml2js.builder.buildObject(params), "utf8").toString("base64")
来替代。
最后,module.exports = app;
这行代码是可选的,它允许你将这个Express应用导出到其他模块中,如果你需要的话。