Node.js(Koa)集成Cashfree网关:签名验证金额格式问题
问题解答:JavaScript中无法用Float类型保留两位小数格式,附Cashfree签名验证解决方案
核心结论
JavaScript的Number类型(包括浮点数)本质是双精度浮点数,仅存储数值本身,不保留格式信息。比如17500.00在JS中会被自动处理为17500,序列化JSON时也只会输出17500,无法实现“以float类型保留两位小数”的需求。
针对Cashfree签名验证的解决方案
你的核心痛点是签名验证需要严格匹配原始请求体的格式(包括金额的两位小数形式),可以通过以下方式解决:
1. 保留原始请求体字符串(Webhook场景)
处理Cashfree的Webhook时,不要直接解析JSON为对象后再序列化(这会丢失金额的格式信息),而是直接使用原始的请求体字符串参与签名计算:
const Koa = require('koa'); const app = new Koa(); // 中间件:获取原始请求体并解析为JSON app.use(async (ctx, next) => { let rawBody = ''; await new Promise(resolve => { ctx.req.on('data', chunk => rawBody += chunk); ctx.req.on('end', resolve); }); ctx.request.rawBody = rawBody; ctx.request.body = JSON.parse(rawBody); await next(); }); app.post('/cashfree-webhook', async (ctx) => { const timestamp = ctx.headers['x-cf-timestamp']; const rawBody = ctx.request.rawBody; // 按Cashfree要求拼接签名 payload const signaturePayload = timestamp + rawBody; // 后续用密钥计算签名并验证(示例逻辑) // const computedSignature = crypto.createHmac('sha256', CASHFREE_SECRET).update(signaturePayload).digest('base64'); // if (computedSignature !== ctx.headers['x-cf-signature']) { ... } // 业务逻辑使用解析后的对象即可,金额数值不影响后续处理 const orderAmount = ctx.request.body.data.order.order_amount; });
2. 格式化金额字符串(主动发起支付请求场景)
如果是向Cashfree发起支付请求,需要构造符合要求的请求体时,直接将金额格式化为两位小数的字符串类型:
function formatAmount(amount) { return parseFloat(amount).toFixed(2); } // 构造请求体 const paymentRequest = { order_id: 'order_xxxx', order_amount: formatAmount(17500), // 输出 "17500.00" order_currency: 'INR' }; // 发送请求时直接序列化该对象即可
关键说明
Cashfree的签名验证依赖原始请求数据的字节一致性,只要保证签名计算时使用的是未被修改的原始请求体(或严格按要求格式化后的字符串),就能通过验证,无需纠结JS变量的数值格式。
内容的提问来源于stack exchange,提问作者Akhilesh Muchhala
相关产品推荐
相关产品推荐

