如何将Stripe Webhook响应数据存储到MySQL数据库
实现Stripe Webhook事件存储到MySQL(Node.js后端)
前置准备
确保你已安装Node.js和MySQL,且MySQL服务正常运行。
1. 安装依赖
在Node.js项目根目录执行:
npm install mysql2 stripe express
mysql2:支持Promise的MySQL驱动,适配异步操作stripe:Stripe官方SDKexpress:搭建Webhook的HTTP服务
2. 配置MySQL连接
创建db.js文件,管理数据库连接池:
const mysql = require('mysql2/promise'); // 创建连接池(比单连接更高效稳定) const pool = mysql.createPool({ host: 'localhost', // 本地开发填localhost,线上填对应服务器地址 user: 'root', // MySQL用户名 password: '你的MySQL密码', // 替换为你的密码 database: '你的数据库名', // 提前在MySQL中创建好目标数据库 waitForConnections: true, connectionLimit: 10, queueLimit: 0 }); module.exports = pool;
3. 创建Stripe事件存储表
打开MySQL客户端(命令行/Navicat等),执行SQL创建表:
CREATE TABLE stripe_events ( id VARCHAR(255) PRIMARY KEY, -- Stripe事件全局唯一ID event_type VARCHAR(100) NOT NULL, -- 事件类型(如checkout.session.completed) created_at BIGINT NOT NULL, -- Stripe事件生成时间戳 data JSON NOT NULL, -- 事件原始数据,用JSON格式存储 processed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- 本地存储时间 );
如果需要针对特定事件存结构化数据(比如单独的订单表),后续可扩展,先从通用事件表上手。
4. 编写Webhook处理及存储逻辑
创建server.js作为后端核心文件:
const express = require('express'); const stripe = require('stripe')('你的Stripe秘钥'); // 替换为你的Stripe秘钥 const pool = require('./db.js'); const app = express(); // 解析Stripe Webhook的原始请求体(必须用raw格式,不能用json) app.post('/stripe-webhook', express.raw({type: 'application/json'}), async (req, res) => { const sig = req.headers['stripe-signature']; const webhookSecret = '你的Stripe Webhook签名秘钥'; // 替换为后台获取的签名秘钥 let event; try { // 验证Webhook签名,防止伪造请求 event = stripe.webhooks.constructEvent(req.body, sig, webhookSecret); } catch (err) { console.log(`Webhook验证失败: ${err.message}`); return res.status(400).send(`Webhook Error: ${err.message}`); } // 通用事件存储函数 const saveStripeEvent = async (event) => { try { await pool.execute( 'INSERT INTO stripe_events (id, event_type, created_at, data) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE data = ?, processed_at = CURRENT_TIMESTAMP', [event.id, event.type, event.created, JSON.stringify(event.data.object), JSON.stringify(event.data.object)] ); console.log(`事件 ${event.id} 已存储/更新`); } catch (dbErr) { console.error(`存储事件失败: ${dbErr.message}`); } }; // 按事件类型分支处理 switch (event.type) { case 'checkout.session.completed': const checkoutSession = event.data.object; console.log('结账会话完成:', checkoutSession.id); // 可在此添加额外逻辑(如更新业务订单状态) await saveStripeEvent(event); break; case 'payment.intent.succeeded': const paymentIntent = event.data.object; console.log('支付成功:', paymentIntent.id); await saveStripeEvent(event); break; case 'payment.intent.failed': const failedPayment = event.data.object; console.log('支付失败:', failedPayment.id); await saveStripeEvent(event); break; // 可继续添加需要处理的其他事件类型 default: console.log(`未处理的事件类型: ${event.type}`); // 可选:存储未处理事件 await saveStripeEvent(event); } // 返回200给Stripe,确认已接收事件 res.json({received: true}); }); // 启动服务,监听端口 const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`服务运行在端口 ${PORT}`); });
关键说明
- 签名验证:必须保留,这是Stripe Webhook的安全机制,签名秘钥在Stripe后台Webhook设置中获取。
- 连接池:避免频繁创建销毁数据库连接,提升性能。
- 重复事件处理:
ON DUPLICATE KEY UPDATE避免Stripe重复发送事件导致的主键冲突,同时更新最新数据。 - JSON存储:用JSON类型存原始数据,方便后续筛选查询,若需结构化存储可后续拆分表。
测试与部署
- 本地测试:用Stripe CLI模拟事件,命令:
stripe listen --forward-to localhost:3000/stripe-webhook - 线上部署:将Node.js服务部署到云平台(Vercel/Heroku/EC2等),在Stripe后台配置Webhook端点为
你的服务地址+/stripe-webhook
内容的提问来源于stack exchange,提问作者flutter dev2
相关产品推荐
相关产品推荐

