決済ボタンを押したのに、画面がしばらく固まったままだと不安になります。もう一度押したくなりますよね。
でも、2回押したら2回決済されてしまうのでは?
よく設計されたシステムなら、そうはなりません。それを保証する性質には名前があります。
冪等性です。
バックエンドのドキュメント、HTTP仕様、決済APIガイドで必ず登場する概念ですが、定義は1行で済みます。難しいのは「なぜこれほど重要なのか」と「どう実装するのか」です。
この記事では、その2つを説明します。
要点をまとめます。
- 冪等性:同じリクエストを1回送っても何度送っても結果が同じになる性質
- 重要な理由:ネットワークは失敗し、失敗したらリトライが必要で、リトライを安全にするには冪等でなければならない
- HTTPではGET・PUT・DELETEが冪等で、POSTは冪等ではない
- POSTを安全にする実務上の仕組みがIdempotency-Key
定義:何度行っても1回行ったのと同じ
冪等性は数学に由来する言葉です。ある演算fがf(f(x)) = f(x)を満たすとき、冪等であるといいます。
絶対値関数がよい例です。 |−5| = 5で、 |5| = 5です。
1回適用しても100回適用しても、結果は同じです。
APIに適用すると、次のようになります。
同じリクエストを1回送ってもN回送っても、サーバーの状態は同じです。
注意点は、レスポンスが同じでなければならないという意味ではなく、サーバーの状態が同じでなければならないということです。2回目のDELETEリクエストが404を返しても、「そのリソースが存在しない」というサーバー状態は同じなので冪等です。
日常の例ならエレベーターのボタンです。5階のボタンを5回押しても、エレベーターは5階へ1回行くだけです。
一方、「5階上へ移動」するボタンなら、押すたびに結果が変わります。前者が冪等、後者が非冪等です。
なぜ重要か:ネットワークは必ず失敗する
冪等性が重要な理由は、1つのシナリオで説明できます。
クライアントが決済リクエストを送信し、サーバーが決済を処理しました。
しかし、レスポンスが戻る途中でネットワークが切断されました。
クライアントには、リクエストがサーバーに届く前に失敗したのか(決済されていない)、処理後にレスポンスだけが失われたのか(決済済み)を知る方法がありません。
どちらの場合も、結果は同じタイムアウトに見えるからです。
選択肢は2つだけです。リトライを諦めるか(決済されていないかもしれない)、リトライするか(済んでいれば二重決済になる)。どちらも困ります。
冪等性がこのジレンマをなくします。リクエストが冪等なら、「分からなければもう一度送る」が常に安全な戦略になります。
自動リトライ、メッセージキューのat-least-once配信、クライアントでの連打による更新も、すべて恐れる必要がなくなります。
分散システムの設計書で「リトライは冪等な処理にだけ設定する」と繰り返し書かれる理由です。
HTTPメソッドで見る冪等性
HTTP仕様(RFC 9110)では、メソッドごとの冪等性が定義されています。
| メソッド | 冪等? | 理由 |
|---|---|---|
| GET | O | 参照は状態を変更しない |
| PUT | O | 「この値に置き換える」は何度行っても同じ値 |
| DELETE | O | 「削除する」は何度行っても削除済みの状態 |
| POST | X | 「新しく作る」は呼ぶたびに1つずつ増える |
| PATCH | 条件付き | 「このフィールドをXにする」は冪等、「1加える」は非冪等 |
PUTとPOSTの対比が重要です。PUTは「結果の状態」を指定するため冪等で、POSTは「行為」を指示するため非冪等です。
PATCHは内容によって異なります。
ブラウザで戻るボタンからPOSTページに戻ったとき、「フォームを再送信しますか?」と警告されるのも、POSTの再送信が安全でないとブラウザが知っているからです。
実務上の仕組み、冪等性キー
しかし、会員登録、注文作成、決済は本質的にPOSTです。非冪等な処理を避けることはできません。
そこで、非冪等なリクエストを冪等にする仕組みが登場しました。Idempotency-Keyです。
動作は単純です。
- クライアントはリクエストごとに一意のキー(通常はUUID)を生成し、ヘッダーに入れて送信する
- サーバーは初めて見るキーなら通常どおり処理し、キーとともにレスポンスを保存する
- 同じキーで再び届いたら処理せず、保存済みのレスポンスをそのまま返す
リトライでもダブルクリックでも、同じキーである限りサーバーは1回だけ処理します。StripeやToss Paymentsなどの決済APIが実際にこのヘッダーをサポートしており、決済連携ガイドでも必須項目として扱われています。
クライアント側の細かな注意点が1つあります。「リトライ時は同じキーを使う」ことです。
リトライごとに新しいキーを作ると、サーバーには別のリクエストに見えるからです。キーは「同じ意図のリクエスト」単位で作成します。
まとめ
- 冪等性とは、同じリクエストを何度送ってもサーバー状態が同じになる性質です(f(f(x)) = f(x))
- ネットワーク障害で「成功したか分からない」状況では、冪等であって初めてリトライが安全になります
- HTTP:GET・PUT・DELETEは冪等、POSTは非冪等、PATCHは内容によって異なる
- PUTは結果の状態を指定するため冪等、POSTは行為を指示するため非冪等
- 非冪等なPOSTはIdempotency-Keyで冪等にする — 同じキーなら1回だけ処理
- リトライ時は必ず同じキーを再利用します。キーは「同じ意図のリクエスト」単位です

