如何使用Stripe防止重复收费?

13
我正在使用Stripe允许我的客户保存信用卡信息并支付带有唯一标识符的发票。支付时,我使用表单将信用卡ID(由Stripe提供)发送到我的服务器上,然后控制器对其进行扣款。然后我在我的一侧将发票标记为已付款。
事实证明,如果我很快双击表单的提交按钮,我会发送两个POST请求,因此卡片最终被收取两次费用,因为第二个POST请求到达我的服务器时,来自第一次单击的服务器到Stripe API的POST请求还没有完成,即发票尚未标记为已付款。
我考虑在第一次单击后禁用表单提交按钮,但我感觉可能有更简洁的方法。
在Stripe方面,是否有防止重复收费的方法(也许使用我的发票ID)?如果没有,在我的端上,最好的后端方法是什么?

2
在表单中的一个隐藏字段中放置一个唯一的交易ID(它只需要是用户ID和时间戳的哈希值,或类似的东西),并让您的服务器记住它发送到Stripe的交易ID,并拒绝发送重复提交。 - Mike Scott
3个回答

21

在第一次点击后禁用表单提交绝对是最简单的实现方法。

另一种方法是使用幂等请求,可以在这里找到相关文档。其思想是在向Stripe的API发出请求时传递一个唯一标识符,以确保您只能运行此事务一次。如果您使用完全相同的幂等键重新运行查询,则会获得来自第一次调用的原始响应,这确保您永远不会在您的网站上为同一“事务”创建2个收费。


6

3
正如其他答案所提到的那样,您可以使用幂等请求来防止重复收费。这是我实施的方式:
checkout.php中:
<?php
function rand_string( $length ) {
    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    return substr(str_shuffle($chars),0,$length);
}
$idempotency = rand_string(8);
?>
 ...
<form method="post" action="payment.php">
<input type="hidden" name="idempotency" id="idempotency" value="<?=$idempotency?>">
...
</form>
...

payment.php 中:
<?php
$idempotency = preg_replace('/[^a-z\d]/im', '', $_POST['idempotency']);
...

try {
    $charge = \Stripe\Charge::create(
        ["amount" => $price,
        "currency" => $currency,
        "description" => $invoiceid,
        "customer" => $customer->id ], 
    ["idempotency_key" => $idempotency,]);
}catch(Exception $e) {
    $api_error = $e->getMessage();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接