Mpesa Webhook开发:如何从Name/Value对象数组提取值赋值变量
M-Pesa支付Webhook回调元数据字段提取实现方案
你拿到的CallbackMetadata.Item是键值对数组结构:每个数组元素的Name字段存字段名,Value字段存对应值,部分字段(如示例中的Balance)可能不返回Value属性,提取时做好空值兼容即可。
实现方式1:遍历匹配字段(兼容性最优)
直接循环数组匹配Name值赋值给预定义变量,不需要额外ES语法支持,直接替换你代码中// populate vars with their values注释位置即可:
if (ResultCode === 0) { // 遍历元数据匹配字段 for (const item of CallbackMetadata) { switch(item.Name) { case 'Amount': Amount = item.Value; break; case 'MpesaReceiptNumber': ReceiptNumber = item.Value; break; case 'TransactionDate': TransactionDate = item.Value; break; case 'PhoneNumber': PhoneNumber = item.Value; break; } } // 必要字段非空校验 if (!Amount || !ReceiptNumber || !TransactionDate || !PhoneNumber) { console.log("回调元数据缺失必要字段", {Amount, ReceiptNumber, TransactionDate, PhoneNumber}); return res.status(400).json({message: "invalid callback metadata"}); } // 组装响应对象 const mpesaResponseObject = { Amount, ReceiptNo: ReceiptNumber, PhoneNumber, TransactionDate }; }
实现方式2:数组转普通对象后取值
代码更简洁,先把键值对数组转成常规对象,再直接按属性名取值:
if (ResultCode === 0) { // 将元数据数组转换为 {字段名: 字段值} 格式的普通对象 const metadataMap = Object.fromEntries( CallbackMetadata.map(item => [item.Name, item.Value]) ); // 直接取值赋值 Amount = metadataMap.Amount; ReceiptNumber = metadataMap.MpesaReceiptNumber; TransactionDate = metadataMap.TransactionDate; PhoneNumber = metadataMap.PhoneNumber; const mpesaResponseObject = { Amount, ReceiptNo: ReceiptNumber, PhoneNumber, TransactionDate }; }
注意事项:
- 回调返回的
TransactionDate是YYYYMMDDHHmmss格式的数字,不是标准时间戳,后续做日期处理时需要先转字符串再做格式化PhoneNumber字段已经携带国家码前缀,不需要额外拼接- 接口处理完成后要及时返回200响应,否则M-Pesa回调服务会重复推送请求
修正后完整业务代码
const express = require("express"); const prettyjson = require("prettyjson"); const Router = express.Router(); Router.post("/stk-webhook", async (req, res) => { let CallbackMetadata; let ResultCode; let Amount; let ReceiptNumber; let TransactionDate; let PhoneNumber; let mpesaResponseObject; console.log("_____________RECEIVED_MPESA_WEBHOOK________"); console.log(prettyjson.render(req.body)); try { ResultCode = req.body.Body.stkCallback.ResultCode; CallbackMetadata = req.body.Body.stkCallback.CallbackMetadata.Item; if (ResultCode === 0) { const metadataMap = Object.fromEntries( CallbackMetadata.map(item => [item.Name, item.Value]) ); Amount = metadataMap.Amount; ReceiptNumber = metadataMap.MpesaReceiptNumber; TransactionDate = metadataMap.TransactionDate; PhoneNumber = metadataMap.PhoneNumber; mpesaResponseObject = { Amount, ReceiptNo: ReceiptNumber, PhoneNumber, TransactionDate }; // 支付成功后续业务逻辑写在此处 res.status(200).json({message: "callback received success"}); } else { console.log("You cancelled transaction"); return res.status(400).json({ message: "you cancelled transaction" }); } console.log(mpesaResponseObject); } catch (error) { console.log(error); res.status(500).json({message: "server process error"}); } }); module.exports = Router;
内容的提问来源于stack exchange,提问作者MAXWEL OCHIENG
相关产品推荐
相关产品推荐

