Skip to content

Node.js 示例

示例为:POST /payIn/orders/createAndPay,签名串为 timestamp|nonce|rawBody

javascript
const crypto = require("crypto");

function sign(timestamp, nonce, body, secret) {
  const signData = `${timestamp}|${nonce}|${body}`;
  return crypto.createHmac("sha256", secret).update(signData).digest("base64");
}

const body = JSON.stringify({
  merchantOrderNo: "M202412220001",
  amount: "100.00",
  currency: "USD",
  methodCode: "INTERNATIONAL_CARD",
  methodData: {
    cardNumber: "4111111111111111",
    expiryMonth: "12",
    expiryYear: "27",
    securityCode: "123"
  }
});
const timestamp = Date.now().toString();
const nonce = "b2b2f3b6a6f24a4ba3dcd0e777c9a888";
const signature = sign(timestamp, nonce, body, "sk_test_9f3b8a2d7c1e4f6a8b0c2d4e6f8a1b3c");

// 用 axios/fetch 发送请求并设置 Headers:
// X-Merchant-Id, X-Timestamp, X-Nonce, X-Sign

验签示例(回调)

rawBody 为实际接收的原始 JSON 字符串

javascript
const crypto = require("crypto");

function sign(timestamp, nonce, body, secret) {
  const signData = `${timestamp}|${nonce}|${body}`;
  return crypto.createHmac("sha256", secret).update(signData).digest("base64");
}

function verify(timestamp, nonce, rawBody, secret, signHeader) {
  const expected = sign(timestamp, nonce, rawBody, secret);
  const expectedBuf = Buffer.from(expected);
  const signBuf = Buffer.from(signHeader);
  if (expectedBuf.length !== signBuf.length) {
    return false;
  }
  return crypto.timingSafeEqual(expectedBuf, signBuf);
}

const rawBody = '{"payNo":"P202312230001","tradeStatus":"SUCCESS"}';
const timestamp = "1734921005000";
const nonce = "b2b2f3b6a6f24a4ba3dcd0e777c9a888";
const signHeader = "base64_signature_from_header";

const ok = verify(timestamp, nonce, rawBody, "sk_test_9f3b8a2d7c1e4f6a8b0c2d4e6f8a1b3c", signHeader);
console.log(ok);