You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel集成Stripe时支付失败但订单仍创建问题排查

Stripe支付失败仍创建订单的问题排查与修复

核心问题定位

支付失败却生成订单,本质是订单创建逻辑和支付结果验证的执行顺序错误,或者支付结果验证环节缺失/失效。

常见错误场景及修复方案

1. Laravel端:订单创建在支付验证之前

错误示例

如果你的Payment Controller先执行订单保存,再验证支付状态,就会导致支付失败后订单已经入库:

public function store(Request $request) {
    // 直接创建订单,未验证支付
    $order = Order::create($request->all());
    
    // 后续才验证支付,失败时订单已存在
    $paymentIntent = \Stripe\PaymentIntent::retrieve($request->payment_intent_id);
    if ($paymentIntent->status !== 'succeeded') {
        return response()->json(['error' => '支付失败'], 400);
    }
    
    return response()->json(['success' => true]);
}

修正方案

先通过Stripe API验证支付状态,确认成功后再创建订单:

public function store(Request $request) {
    // 1. 优先验证Stripe支付结果
    try {
        $paymentIntent = \Stripe\PaymentIntent::retrieve($request->payment_intent_id);
        if ($paymentIntent->status !== 'succeeded') {
            return response()->json(['error' => '支付未完成'], 400);
        }
    } catch (\Exception $e) {
        return response()->json(['error' => '支付验证失败:'.$e->getMessage()], 400);
    }
    
    // 2. 支付成功后再创建订单
    $order = Order::create($request->all());
    
    return response()->json(['success' => true, 'order' => $order]);
}

2. Laravel端:Webhook支付失败事件未正确处理

如果依赖Stripe Webhook同步支付状态,可能存在以下问题:

  • 未监听payment_intent.payment_failed事件
  • Webhook签名验证失败导致事件未处理,订单已提前标记为完成

排查与修复

  • 登录Stripe Dashboard查看Webhook日志,确认失败事件是否成功发送到你的Laravel服务
  • 确保Webhook路由正确验证签名并处理失败事件:
public function handleWebhook(Request $request) {
    $payload = $request->getContent();
    $sigHeader = $request->header('Stripe-Signature');
    $webhookSecret = config('services.stripe.webhook_secret');
    
    try {
        $event = \Stripe\Webhook::constructEvent(
            $payload, $sigHeader, $webhookSecret
        );
    } catch (\Exception $e) {
        return response()->json(['error' => $e->getMessage()], 400);
    }
    
    // 处理支付失败事件,更新订单状态
    if ($event->type === 'payment_intent.payment_failed') {
        $paymentIntent = $event->data->object;
        $order = Order::where('payment_intent_id', $paymentIntent->id)->first();
        if ($order) {
            $order->update(['status' => 'failed']);
        }
    }
    
    return response()->json(['success' => true]);
}

注意:用Webhook模式时,订单创建后需默认标记为pending,待Webhook确认支付成功后再改为paid,避免直接设置为已支付状态。

3. Flutter端:未判断支付结果就发起订单请求

错误示例

如果Flutter代码在支付失败时仍调用了Laravel的订单创建接口,也会导致无效订单生成:

Stripe.instance.confirmPayment(
    paymentIntentClientSecret: clientSecret,
    data: PaymentMethodCard(
        number: cardNumber,
        expMonth: expMonth,
        expYear: expYear,
        cvc: cvc,
    ),
).then((value) {
    // 未判断支付状态就发送订单请求
    http.post(Uri.parse('https://your-api.com/orders'), body: orderData);
}).catchError((error) {
    print(error);
});

修正方案

仅在支付成功时才调用订单创建接口:

try {
    final paymentResult = await Stripe.instance.confirmPayment(
        paymentIntentClientSecret: clientSecret,
        data: PaymentMethodCard(
            number: cardNumber,
            expMonth: expMonth,
            expYear: expYear,
            cvc: cvc,
        ),
    );
    
    if (paymentResult.status == PaymentIntentsStatus.Succeeded) {
        // 支付成功后才提交订单
        await http.post(Uri.parse('https://your-api.com/orders'), body: {
            ...orderData,
            'payment_intent_id': paymentResult.paymentIntentId,
        });
    } else {
        print('支付失败:${paymentResult.status}');
    }
} catch (e) {
    print('支付错误:$e');
}

关键验证原则

  • 永远不要信任前端传来的支付成功状态,必须在Laravel端通过Stripe API或Webhook二次验证
  • 订单状态需区分pending、paid、failed三种状态,避免直接创建为已支付状态
  • 确保Stripe API调用时捕获异常(比如网络错误、无效的payment_intent_id)

内容的提问来源于stack exchange,提问作者Pramod Yadav

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 19:45:43