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

Stripe支付异常:无法存储数据到数据库,且出现Token重复使用报错

Stripe支付错误排查与修复

错误原因分析

  1. Token重复使用:Stripe支付令牌(tok_xxx)是一次性凭证,当你用它创建Customer后,令牌会立即失效。如果同一令牌被重复提交到后端,就会触发You cannot use a Stripe token more than once错误。你能在Stripe仪表盘看到测试金额,说明第一次请求已成功创建Charge,但后续重复执行了相同逻辑,导致报错。
  2. 数据库未存储数据:你的代码仅处理了Stripe的API调用,完全没有数据库插入逻辑;且致命错误会直接中断代码执行,即使第一次请求成功,也没机会把数据写入数据库。

修复步骤

1. 解决Token重复使用问题

  • 前端防重复提交:给支付按钮添加置灰逻辑,用户点击后立即禁用按钮,避免多次提交同一令牌。
  • 后端幂等性处理:给Stripe API请求添加idempotency_key参数,确保同一请求只会被执行一次。用你生成的$orderID作为幂等键即可。
  • 确保令牌单次使用:前端每次发起支付请求时,必须通过Stripe.js/Elements重新生成新令牌,禁止复用旧令牌。

2. 修复数据库存储问题

  • 在Stripe Charge创建成功后,添加数据库插入代码,将订单、用户、支付相关信息写入数据库。
  • 用try-catch包裹Stripe API调用,捕获错误并记录日志,避免致命错误中断流程。

修改后的代码示例

// set API Key
$stripe = array(
    "SecretKey"=>"sk_test_51PNnHTGMcptyt0mOGyt8G6VmAvXhlJ7ojBpzdlI1Ey2JLrDghSZ2Nz5UszwSJr9madoDm",
    "PublishableKey"=>"pk_test_51PNnHTGMcptyt0mOSgd8HrIaMr0mj0DM6lyd7W2EqlnzL3L4CHKJ0Yf2EPd9Qid8dOeGXNcwK8j"
);

\Stripe\Stripe::setApiKey($stripe['SecretKey']);

// Generate Unique order ID 
$orderID = strtoupper(str_replace('.','',uniqid('', true)));
// 准备幂等键
$idempotencyKey = $orderID;

try {
    // Add customer to stripe - 加入幂等键
    $customer = \Stripe\Customer::create(array( 
        'email' => $email, 
        'source'  => $token,
        'name' => $name,
        'description'=>$des
    ), array('idempotency_key' => $idempotencyKey));

    // Convert price to cents 
    $itemPrice = ($price*100);
    $currency = "usd";

    // Charge a credit or a debit card - 加入幂等键
    $charge = \Stripe\Charge::create(array( 
        'amount'   => $itemPrice, 
        'currency' => $currency, 
        'customer' => $customer->id, 
        'description' => $des
    ), array('idempotency_key' => $idempotencyKey));

    // --------------------------
    // 数据库插入逻辑示例(根据你的表结构调整)
    // --------------------------
    $pdo = new PDO('mysql:host=localhost;dbname=your_database', 'db_user', 'db_password');
    $stmt = $pdo->prepare("INSERT INTO orders (order_id, email, stripe_customer_id, stripe_charge_id, amount, currency, description) VALUES (?, ?, ?, ?, ?, ?, ?)");
    $stmt->execute([
        $orderID,
        $email,
        $customer->id,
        $charge->id,
        $price, // 存储原金额(非分单位)
        $currency,
        $des
    ]);

    // 支付成功跳转
    header("Location: success.php?order=$orderID");
    exit;

} catch (\Stripe\Exception\ApiErrorException $e) {
    // 记录Stripe错误日志
    error_log('Stripe Error: ' . $e->getMessage());
    // 返回错误提示
    header("Location: payment_error.php?msg=" . urlencode($e->getMessage()));
    exit;
} catch (PDOException $e) {
    // 记录数据库错误日志
    error_log('DB Error: ' . $e->getMessage());
    header("Location: payment_error.php?msg=订单存储失败");
    exit;
}

额外注意事项

  • 禁止将Stripe Secret Key暴露在前端或公开代码中,仅在后端环境使用。
  • 测试时使用Stripe官方测试卡号(如4242 4242 4242 4242),避免使用真实卡信息。
  • 建议配置Stripe Webhook接收支付状态通知,确保后端流程中断时,仍能同步支付结果到数据库。

内容的提问来源于stack exchange,提问作者Nazmul Hossain Pappu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 17:25:54