我使用Stripe允许我的客户保存信用卡并支付发票(具有唯一ID)。在付款时,我使用表单将带有卡ID(由条带提供)的POST请求发送到我的服务器,然后控制器对其进行收费。然后我将发票标记为支付给我。
事实证明,如果我足够快地双击我的表单提交按钮,我会发送两个POST请求,并且这些卡最终会被收取两次费用,因为当第二个POST请求到达我的服务器时,POST请求来自我的服务器到条纹API(从第一次点击)尚未完成,因此发票尚未标记为付款。
我考虑在第一次点击后禁用表单提交按钮,但我觉得可能有一种更清洁的方式。
Stripe的一方是否有防止重复收费(可能使用我的发票ID)?如果不是最好的后端方法在我身边做什么呢?
答案 0 :(得分:6)
首次点击后禁用表单提交绝对是实现此目的的最简单方法。
另一种方法是使用记录为here的幂等请求。我们的想法是在向Stripe的API发出请求时传递唯一标识符,以确保您只能运行此事务一次。如果您使用完全相同的幂等关键字重新运行查询,您将从第一次调用中获得原始响应,这可确保您永远不会为同一个"事务"在您的网站上。
答案 1 :(得分:3)
如其他答案所述,您可以使用Idempotent Requests来防止重复收费。这是我的实现方式:
在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();
}
答案 2 :(得分:2)
是幂等请求是实现此目的的正确方法。
你可以在这里参考
https://stripe.com/docs/api#idempotent_requests
另一个可以实现的简单解决方案是通过跟踪条带api调用来使用状态机。