如何通过PHP GET传递JavaScript变量至Millikart支付网关
实现在线支付表单的完整方案
我来帮你搞定这个在线支付表单的实现,咱们从你最关心的金额转换开始,一步步拆解所有环节:
1. 处理交易金额转换(JS计算后的变量转整数格式)
你提到交易金额是JS计算得到的变量,需要转换成整数格式(比如$50.25转成5025),这里要注意浮点数精度问题——直接乘以100可能会出现类似0.1+0.2=0.30000000000000004的误差,所以推荐用Math.round来确保准确性:
// 假设这是你JS计算得到的金额(比如从购物车总价、输入框获取等) const calculatedAmount = 50.25; // 转换为整数格式:乘以100后取整 const amount = Math.round(calculatedAmount * 100); // 结果:5025
如果你的金额是字符串格式(比如用户输入的"50.25"),先转成数字再处理:
const amountStr = "50.25"; const amount = Math.round(parseFloat(amountStr) * 100);
2. 收集所有必填参数
按支付网关要求整理参数:
mid:你的商户ID(固定值,比如"Test")amount:上面转换后的整数金额currency:ISO 4217货币代码(比如阿塞拜疆马纳特是944)description:交易描述(比如"test1000",可根据业务动态生成)reference:唯一交易参考号(建议用时间戳+随机字符串生成,确保不重复)language:可选语言(az/en/ru,比如选"az")key:商户密钥(重要提醒:绝对不能把密钥写在前端代码里!建议后端生成签名,避免密钥泄露)
3. 生成Signature签名
根据你提供的PHP逻辑,转换成JS版本的签名生成函数。注意参数顺序必须严格和示例一致,否则签名会验证失败:
function generateSignature(mid, amount, currency, description, reference, language, key) { // 处理description为空的情况,用"0"代替 const descPart = description ? `${description.length}${description}` : "0"; // 按顺序拼接所有参数的长度+值,最后加密钥 const signatureStr = `${mid.length}${mid}` + `${amount.toString().length}${amount}` + `${currency.length}${currency}` + descPart + `${reference.length}${reference}` + `${language.length}${language}` + key; // 生成MD5哈希并转大写 // 注意:JS本身没有内置MD5函数,你可以用第三方库(如crypto-js)或者后端生成 // 以下是用crypto-js的示例(需要先引入库) const md5Hash = CryptoJS.MD5(signatureStr).toString(); return md5Hash.toUpperCase(); }
关于签名的安全提醒
如果把密钥放在前端,任何人都能通过查看源码获取,会导致交易被篡改的风险。更安全的做法是:前端把计算好的金额、描述、参考号等参数传给后端接口,后端用密钥生成签名,再返回完整的支付跳转URL给前端。
4. 拼接支付跳转URL
把所有参数拼接成符合要求的URL,注意对参数值进行URL编码:
// 假设已经获取到所有参数和生成的signature const mid = "Test"; const currency = "944"; const description = "test1000"; // 生成唯一参考号示例:时间戳+随机字符串 const reference = `T${Date.now()}${Math.random().toString(16).slice(2, 10)}`; const language = "az"; const signature = generateSignature(mid, amount, currency, description, reference, language, YOUR_KEY); // 注意YOUR_KEY如果是前端用的话要替换,但不建议 // 拼接URL参数 const params = new URLSearchParams({ mid, amount, currency, description, reference, language, signature }); // 完整支付URL const paymentUrl = `https://test.millikart.az:7444/gateway/payment/register?${params.toString()}`;
5. 触发支付跳转
给你的支付按钮添加点击事件,执行上述逻辑后跳转:
<button id="payBtn">发起支付</button> <script> document.getElementById("payBtn").addEventListener("click", async () => { // 1. 计算并转换金额 const calculatedAmount = 50.25; // 替换成你的实际计算逻辑 const amount = Math.round(calculatedAmount * 100); // 2. 如果是后端生成签名,这里调用接口获取支付URL // const response = await fetch('/api/generate-payment-url', { // method: 'POST', // headers: { 'Content-Type': 'application/json' }, // body: JSON.stringify({ amount, description: "test1000", language: "az" }) // }); // const { paymentUrl } = await response.json(); // 3. 跳转到支付页面 window.location.href = paymentUrl; }); </script>
关键注意事项
- 参数顺序:生成签名时的参数顺序必须严格按照
mid → amount → currency → description → reference → language → key的顺序,不能打乱。 - 金额精度:一定要用
Math.round处理浮点数,避免转换后出现错误的整数(比如50.259转成5026而不是5025)。 - 签名安全:密钥绝对不能暴露在前端,后端生成签名是最优方案。
内容的提问来源于stack exchange,提问作者Nahid Mirzayev
相关产品推荐
相关产品推荐

