Stripeを使用して、顧客がクレジットカードを保存し、請求書(一意のIDを持つ)を支払うことができるようにしています。支払い時に、フォームを使用してPOSTカードID(ストライプで提供)のリクエストをサーバーに送信し、コントローラーが請求します。次に、請求書に支払い済みのマークを付けました。 。
フォームの送信ボタンをすばやくダブルクリックすると、2つのPOSTリクエストが送信され、2番目のPOST =リクエストがサーバーに到着し、POSTサーバーからStripeAPIへのリクエスト(最初のクリックから)が完了していないため、請求書はまだ支払い済みとしてマークされていません。
最初のクリック後にフォーム送信ボタンを無効にすることを検討していますが、よりクリーンな方法があると思います。
(おそらく私の請求書IDを使用して)請求の重複を防ぐためにStripeの側にありますか?そうでない場合、私の側でこれを行うための最良のバックエンド方法は何でしょうか?
最初のクリック後にフォーム送信を無効にすることは、これを実装する最も簡単な方法です。
別のアプローチは、文書化されているようにべき等要求を使用することです ここ 。 StripeのAPIにリクエストを送信するときに一意の識別子を渡して、このトランザクションを1回だけ実行できるようにするという考え方です。まったく同じべき等キーを使用してクエリを再実行すると、最初の呼び出しから元の応答が得られます。これにより、Webサイトで同じ「トランザクション」に対して2つの請求が発生することはありません。
はいべき等要求はこれを実装する正しい方法です。
ここでこれを参照できます
https://stripe.com/docs/api#idempotent_requests
実装できるもう1つの簡単なソリューションは、ストライプAPI呼び出しを追跡することによるステートマシンの使用です。
他の回答で述べられているように、 べき等要求 を使用して重複請求を防ぐことができます。これが私がそれを実装する方法です:
オン 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();
}