You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 02:04:55