
本文详解如何通过 stripe webhook 实现支付成功后的数据库操作(如更新订单状态、持久化交易数据),避免依赖前端跳转的不稳定性,确保业务逻辑的可靠性和数据一致性。
本文详解如何通过 stripe webhook 实现支付成功后的数据库操作(如更新订单状态、持久化交易数据),避免依赖前端跳转的不稳定性,确保业务逻辑的可靠性和数据一致性。
在 Stripe 支付流程中,仅靠重定向至 success_url(例如 success.php)执行数据库更新是高风险且不可靠的。用户可能在支付完成后关闭浏览器、网络中断、或页面未完全加载,导致 success.php 根本未被执行——这意味着订单状态卡在“待支付”,而资金已到账,造成业务数据与财务状态严重脱节。
✅ 正确方案:使用 Stripe Webhook(服务端事件回调)
Webhook 是 Stripe 主动向你指定的 https 端点推送事件通知的机制。当支付成功(payment_intent.succeeded)或 Checkout 会话完成(checkout.session.completed)时,Stripe 会实时发送加密签名的 json 事件到你的服务器。你在此端点验证签名、解析事件,并安全执行数据库更新。
? 实现步骤概览
- 创建 Webhook 端点(如 /webhook.php),支持 POST 请求;
- 在 Stripe Dashboard 或 CLI 中注册该端点,并保存 Webhook Signing Secret;
- 在端点中验证事件签名(必须!防止伪造请求);
- 检查事件类型与状态,查询关联的订单并更新数据库;
- 返回 200 OK 响应(Stripe 收到后停止重试);
- (可选)添加幂等处理,避免重复事件导致数据异常。
? 示例:PHP Webhook 处理器(laravel/Lumen 或原生 PHP 均可参考)
// webhook.php require 'vendor/autoload.php'; use StripeStripe; use StripeWebhook; // 配置密钥(请从 .env 或安全配置中心读取) StripeStripe::setApiKey('sk_test_...'); // 私钥用于验证 $endpoint_secret = 'whsec_...'; // Webhook Signing Secret(Dashboard → Developers → Webhooks) $payload = @file_get_contents('php://input'); $sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE'] ?? null; $event = null; try { $event = Webhook::constructEvent($payload, $sig_header, $endpoint_secret); } catch (UnexpectedValueException $e) { http_response_code(400); echo 'Invalid payload'; exit(); } catch (StripeExceptionSignatureVerificationException $e) { http_response_code(400); echo 'Invalid signature'; exit(); } // 处理关键事件 if ($event->type === 'checkout.session.completed') { $session = $event->data->object; $orderId = $session->metadata->order_id ?? null; // 推荐:创建 Session 时通过 metadata 传入订单 ID if ($orderId) { // ✅ 安全更新数据库:标记订单为已支付、记录 payment_id、更新时间等 $pdo = new PDO('mysql:host=localhost;dbname=shop', $user, $pass); $stmt = $pdo->prepare("UPDATE orders SET status = 'paid', payment_id = ?, updated_at = NOW() WHERE id = ?"); $stmt->execute([$session->payment_intent, $orderId]); // 可扩展:发送通知、生成电子发票、触发库存扣减等 error_log("Order #{$orderId} paid successfully via Stripe."); } } http_response_code(200); // 必须返回 200,否则 Stripe 将重试 echo 'OK';
⚠️ 关键注意事项
- 永远不要跳过签名验证:Webhook::constructEvent() 是唯一可信的验证方式,手动解析 Stripe-Signature 头存在安全漏洞;
- metadata 是传递业务上下文的核心:创建 Checkout Session 时,务必通过 ‘metadata’ => [‘order_id’ => ‘ord_123’] 绑定订单标识,避免反查失败;
- 幂等性设计:Webhook 可能重复投递(如网络超时),建议在数据库中增加 webhook_event_id 字段去重,或使用 INSERT … ON DUPLICATE KEY UPDATE;
- 错误处理要静默且快速:不要在 Webhook 中执行耗时操作(如发邮件、调用外部 API),应交由队列异步处理;
- 本地调试推荐 Stripe CLI:运行 stripe listen –forward-to localhost:8000/webhook.php 并用 stripe trigger payment_intent.succeeded 测试。
✅ 总结
将 success.html 替换为 success.php 并直接写入数据库,看似简单,实则埋下数据不一致的隐患。Webhook 是 Stripe 官方推荐、生产环境唯一可靠的事件驱动方案。它解耦了支付结果与业务动作,保障了系统健壮性与财务准确性。立即弃用客户端跳转逻辑,拥抱服务端事件驱动架构——这才是现代支付集成的专业实践。