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

Flutter应用Stripe订阅集成问题:Client Secret格式错误

问题分析与解决方案

核心错误原因

你混淆了Stripe Checkout Session和Payment Intent的client_secret用法:

  • Checkout Session的client_secret并非用于Flutter Stripe SDK的支付确认,且你当前代码里错误地尝试访问$result->client_secret->id(实际上Checkout Session的client_secret是字符串值,不是对象),导致返回了格式完全错误的secret-cus_xxx字符串,触发Flutter端格式校验失败。
  • 另外,Checkout Session的client_secret仅用于后端验证会话状态,前端根本不需要使用它。

第一步:修复PHP后端代码

错误点修正

  1. 删除错误的$clientSecret = $result->client_secret->id;代码行
  2. 改为返回Checkout Session的id给Flutter端,这才是前端需要用的标识

修正后的PHP代码

$stripe = new \Stripe\StripeClient('sk_test_key');
$clientReferenceId = $customerid . '_' . time();
try {
    $result = $stripe->checkout->sessions->create([
        'customer' => $customerid,
        'line_items' => [[
            'price' => $planpriceid,
            'quantity' => 1,
        ]],
        'mode' => 'subscription',
        'success_url' => 'https://domain.app/plan_success_data.php?company_id=&plan_id=&no_of_workers=',
        'cancel_url' => 'https://domain.app/plan_failed.php',
        'client_reference_id' => $clientReferenceId,
    ]);
    
    if (isset($result->id)) {
        $data = [ 
            "status" => true,
            "checkout_session_id" => $result->id, // 返回正确的Checkout Session ID给Flutter
            "client_reference_id" => $result->client_reference_id
        ];
        echo json_encode($data);
    } else {
        $data = [
            "status" => false,
            "stripe_sub_id" => ''
        ];
        echo json_encode($data);
    }
} catch (\Stripe\Exception\ApiErrorException $e) {
    echo json_encode(["status" => false, "error" => $e->getMessage()]);
}

第二步:Flutter端正确集成Stripe Checkout

推荐两种可行方案:

方案1:WebView加载Stripe官方Checkout页面(最简单)

直接利用Stripe托管的Checkout页面,通过WebView加载并监听跳转结果:

import 'package:webview_flutter/webview_flutter.dart';

// 从后端获取checkout_session_id后构造跳转URL
final checkoutUrl = 'https://checkout.stripe.com/pay/$checkoutSessionId';

// 渲染WebView
WebView(
  initialUrl: checkoutUrl,
  javascriptMode: JavascriptMode.unrestricted,
  navigationDelegate: (NavigationRequest request) {
    // 监听成功/取消回调URL,处理支付结果
    if (request.url.startsWith('https://domain.app/plan_success_data.php')) {
      // 支付成功,关闭WebView并更新本地状态
      Navigator.pop(context);
      return NavigationDecision.prevent;
    }
    if (request.url.startsWith('https://domain.app/plan_failed.php')) {
      // 支付取消/失败,关闭WebView
      Navigator.pop(context);
      return NavigationDecision.prevent;
    }
    return NavigationDecision.navigate;
  },
);

方案2:使用Stripe Flutter SDK的嵌入式Checkout

如果要使用SDK原生组件,确保传入正确的Session ID:

import 'package:stripe_checkout/stripe_checkout.dart';

// 初始化Stripe(仅传入Publishable Key)
final stripe = Stripe(
  publishableKey: 'pk_test_your_publishable_key',
);

// 调用后端获取checkout_session_id后发起支付
final sessionId = 'cs_test_xxx'; // 后端返回的checkout_session_id
final result = await stripe.redirectToCheckout(
  sessionId: sessionId,
);

// 处理支付结果
if (result.success) {
  // 支付成功逻辑
} else {
  // 支付失败/取消逻辑
}

关键注意事项

  • 永远不要在Flutter端暴露Stripe Secret Key,所有会话创建、客户操作必须在后端完成
  • 定期更新Stripe PHP SDK和Flutter SDK版本,避免兼容性问题
  • 支付成功后,后端可以通过Webhook监听checkout.session.completed事件,更新本地订阅状态

内容的提问来源于stack exchange,提问作者QuezTest Account

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 04:06:17