如何仅在不存在时创建Stripe PaymentIntent对象?
正确实现每个订单对应唯一PaymentIntent的方案
首先说明你第一个代码无法运行的核心原因:Stripe的retrieve()方法在目标PaymentIntent不存在时,不会返回false,而是直接抛出**Stripe\Exception\InvalidRequestException**异常,因此你的if判断逻辑永远无法执行,反而会直接触发错误中断流程。
下面提供两种可行的实现方案,其中第二种更贴合你追求的“优雅”需求:
方案一:精准异常捕获(Stripe官方常规做法)
避免捕获通用Exception,转而精准捕获Stripe的资源不存在异常,这样能过滤掉网络错误、参数错误等无关异常,逻辑更严谨:
$stripeIntentId = "pi_{$order->id}"; try { // 尝试获取已存在的PaymentIntent $paymentIntent = $stripe->paymentIntents->retrieve($stripeIntentId); } catch (\Stripe\Exception\InvalidRequestException $e) { // 仅当明确是资源不存在时,才创建新的PaymentIntent if ($e->getCode() === 'resource_missing') { $paymentIntent = $stripe->paymentIntents->create([ 'id' => $stripeIntentId, 'amount' => $payAmount, 'currency' => $payCurrency, 'description' => $payDescription, 'automatic_payment_methods' => ['enabled' => true], 'metadata' => ['order_id' => $order->id], ]); } else { // 其他无效请求异常,重新抛出以便上层处理 throw $e; } }
方案二:本地数据库记录关联关系(更优雅的实现)
在你的订单表中新增一个字段(比如stripe_payment_intent_id),存储订单对应的PaymentIntent ID,彻底摆脱异常依赖:
// 先从本地订单数据中检查是否已有关联的PaymentIntent if (empty($order->stripe_payment_intent_id)) { $stripeIntentId = "pi_{$order->id}"; $paymentIntent = $stripe->paymentIntents->create([ 'id' => $stripeIntentId, 'amount' => $payAmount, 'currency' => $payCurrency, 'description' => $payDescription, 'automatic_payment_methods' => ['enabled' => true], 'metadata' => ['order_id' => $order->id], ]); // 将创建好的PaymentIntent ID更新到本地订单记录 $order->update(['stripe_payment_intent_id' => $stripeIntentId]); } else { // 使用本地存储的ID直接获取PaymentIntent $paymentIntent = $stripe->paymentIntents->retrieve($order->stripe_payment_intent_id); }
注意事项
- 创建PaymentIntent时指定
id参数是合法操作,但必须保证ID以pi_开头,且全局唯一(用订单ID做后缀可满足唯一性要求)。 - 如果系统存在并发创建订单的场景,需添加数据库行锁等并发控制机制,避免同一订单重复创建PaymentIntent。
内容的提问来源于stack exchange,提问作者Anders
相关产品推荐
相关产品推荐

