如何将Midtrans Snap返回的JSON支付结果存储到MySQL数据库
Midtrans支付发票存储MySQL实现方案
原有JSON.parse报错原因
你的代码触发JSON.parse报错是逻辑错误导致的:
- Midtrans的
snap.pay回调函数中传入的result参数本身就是标准JS对象,不需要额外做parse转换 - 你的代码通过
+=把格式化后的JSON字符串追加到DOM元素的innerHTML中,此时赋值给stringjson的内容是DOM原有内容+新拼接字符串的混合文本,不是合法的JSON结构,直接parse必然报错 - 把parse后得到的JS对象直接赋值给innerHTML,会被强制转成
[object Object],也不符合展示需求
修复后的前端回调逻辑
不需要做多余的字符串转对象操作,直接使用回调返回的result对象即可,同时把数据发给后端做存储:
<script src="https://app.sandbox.midtrans.com/snap/snap.js"></script> <script type="text/javascript"> document.getElementById('pay-button').onclick = function() { snap.pay('<?php echo $snapToken ?>', { onSuccess: function(result) { // 页面展示结果 document.getElementById('result-json').innerHTML = JSON.stringify(result, null, 2); // 发送结果到后端存储 savePaymentResult(result); }, onPending: function(result) { document.getElementById('result-json').innerHTML = JSON.stringify(result, null, 2); savePaymentResult(result); }, onError: function(result) { document.getElementById('result-json').innerHTML = JSON.stringify(result, null, 2); savePaymentResult(result); } }); }; // 统一处理支付结果上传 function savePaymentResult(paymentData) { fetch('/save_payment.php', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(paymentData) }).then(res => res.json()).then(res => { console.log('支付结果存储状态:', res); }).catch(err => { console.error('存储请求失败:', err); }); } </script>
MySQL存储完整实现流程
- 第一步:创建支付发票数据表
先在MySQL中建表,字段和Midtrans返回的支付字段对应,参考SQL:CREATE TABLE `payment_invoices` ( `id` int UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, `transaction_id` varchar(100) NOT NULL UNIQUE COMMENT 'Midtrans交易ID', `order_id` varchar(100) NOT NULL COMMENT '商户订单号', `status_code` varchar(10) NOT NULL COMMENT '状态码', `status_message` varchar(255) NOT NULL COMMENT '状态描述', `gross_amount` decimal(10,2) NOT NULL COMMENT '交易金额', `payment_type` varchar(50) NOT NULL COMMENT '支付方式', `transaction_time` datetime NOT NULL COMMENT '交易时间', `transaction_status` varchar(20) NOT NULL COMMENT '交易状态', `fraud_status` varchar(20) DEFAULT NULL COMMENT '风控状态', `finish_redirect_url` varchar(255) DEFAULT NULL COMMENT '支付完成跳转地址', `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - 第二步:后端接口做合法性校验
注意:绝对不能直接信任前端传来的支付结果,必须做服务端校验避免伪造支付请求
后端收到前端传来的支付数据后,需要拿到transaction_id或order_id调用Midtrans服务端接口查询真实交易状态,确认返回结果和前端传参一致、交易状态合法后,再做存储操作。 - 第三步:数据入库
校验通过后,把支付字段和数据表字段做映射,通过预处理SQL语句插入到payment_invoices表中即可,避免SQL注入风险。
以PHP后端简单示例为例:<?php // save_payment.php header('Content-Type: application/json'); // 读取前端传的JSON数据 $rawData = file_get_contents('php://input'); $paymentData = json_decode($rawData, true); // 此处省略Midtrans服务端校验交易状态的逻辑,校验通过后再执行入库 // ...... // 连接数据库(替换为你自己的数据库配置) $pdo = new PDO('mysql:host=localhost;dbname=your_db;charset=utf8mb4', 'db_user', 'db_pass'); // 预处理插入语句,重复交易ID则更新状态 $stmt = $pdo->prepare("INSERT INTO payment_invoices (transaction_id, order_id, status_code, status_message, gross_amount, payment_type, transaction_time, transaction_status, fraud_status, finish_redirect_url) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE transaction_status = VALUES(transaction_status), updated_at = CURRENT_TIMESTAMP"); // 绑定参数执行 $stmt->execute([ $paymentData['transaction_id'], $paymentData['order_id'], $paymentData['status_code'], $paymentData['status_message'], $paymentData['gross_amount'], $paymentData['payment_type'], date('Y-m-d H:i:s', strtotime($paymentData['transaction_time'])), $paymentData['transaction_status'], $paymentData['fraud_status'], $paymentData['finish_redirect_url'] ]); echo json_encode(['code' => 0, 'msg' => '存储成功']); - 第四步:后续状态同步兜底
对于pending状态的交易,建议配置Midtrans的Webhook回调,在支付状态变更时主动更新数据库中的交易状态,避免用户提前关闭页面导致前端请求漏发、交易状态不一致的问题。
内容的提问来源于stack exchange,提问作者Jessen Jie
相关产品推荐
相关产品推荐

