web-dev-qa-db-ja.com

RESTでPOSTの重複を避けてください

POSTでREST APIを使用してオブジェクトを作成します。時々、サーバーがオブジェクトを作成しますが、クライアントは切断されますクライアントは201 Createdレスポンスを受信する前に、失敗したPOST=リクエストのみを確認し、後で再試行します。サーバーは喜んで複製オブジェクトを作成します...

他の人はこの問題を抱えていたに違いありませんか?しかし、私はグーグルで検索し、誰もがそれを無視しているようです。

私には2つの解決策があります:

A)代わりにPUTを使用し、クライアントで(GU)IDを作成します。

B)GUID=)をクライアントで作成されたすべてのオブジェクトに追加し、サーバーにUNIQUE- nessを適用させます。

Aは既存のフレームワークにあまりよくマッチせず、Bはハックのように感じます。現実の世界では、他の人々はこれをどのように解決しますか?

編集:

Backbone.jsを使用すると、クライアントでオブジェクトを作成するときにIDとしてGUIDを設定できます。オブジェクトが保存されると、BackboneはPUT要求を実行します。RESTバックエンドは、存在しないIDへのPUTを処理し、設定されています。

37
geon

私は常にBを使用します。サーバー側に問題があるため、DUPを検出します。

8
Kyle Banerjee

このために提案されている別のソリューションは POST Once Exactly(POE) です。この場合、サーバーは使い捨てのPOST URIを生成します。サーバーが405応答を返すようにします。

欠点は、1)POEドラフトが標準化のさらなる進展なしに期限切れになることを許可されたため、2)それを実装するには、クライアントに新しいPOEヘッダーを使用するための変更と、POEセマンティクスを実装するためのサーバーによる追加作業が必要です。

グーグルで検索すると、それを使用しているいくつかのAPIを見つけることができます。

この問題を解決するために私が持っていたもう1つのアイデアは、条件付きPOSTのアイデアです。これについて説明し、 here に関するフィードバックを求めました。

一意のURI生成がクライアント上でPUTできないため、POSTが必要な場合に、重複リソースの作成を防止する最良の方法についてコンセンサスがないようです。

8
Chris Toomey

重複の検出は手間がかかり、非常に複雑になる可能性があります。おそらくネットワーク接続が復元されたために、本物であるが類似した要求が同時に到着する可能性があります。また、ネットワーク接続が切断された場合、繰り返し要求が数時間または数日離れて到着する可能性があります。

他のanwsersでの識別子の説明はすべて、重複したリクエストへの応答でエラーを与えることを目的としていますが、これは通常、クライアントに新しいIDを取得または生成して再試行するよう促します。

この問題を解決するためのシンプルで堅牢なパターンは次のとおりです。サーバーアプリケーションは安全でないリクエストに対するすべての応答を保存し、重複したリクエストを見つけた場合は前のレスポンスを繰り返すことができます他に何もしない.すべての安全でないリクエストに対してこれを行うと、厄介な問題の束を解決します。 「重複」は、クライアント生成のGUIDまたはサーバー生成のシーケンス番号のいずれかである、アプリケーションレベルのIDによって決定されます。この2番目の場合、要求と応答は交換のみに使用する必要があります専用のステップにより、クライアントは自分が大切な何かを手に入れていると思うようになるため、このソリューションが気に入っています。独自の識別子を生成できる場合、この行をループ内に置き、要求には新しいIDが付けられます。

このスキームを使用すると、すべてのPOSTは空になり、POSTはアクション識別子の取得にのみ使用されます。すべてのPUTとDELETEは完全にべき等です。このパターンの最も良い点は、Kung-Fu(Panda)の品質です。弱点があります:クライアントが予期しない応答を受け取るたびに要求を繰り返し、それを力に変える傾向があります:- )

私は少しGoogleのドキュメントを持っています here もし気にするなら。

5
bbsimonbb

2段階のアプローチを試すことができます。オブジェクトの作成をリクエストすると、トークンが返されます。次に、2番目の要求で、トークンを使用してステータスを要求します。トークンを使用してステータスが要求されるまで、「ステージング」状態のままにします。

クライアントが最初のリクエストの後に切断した場合、クライアントはトークンを持たず、オブジェクトは無期限に、または別のプロセスで削除するまで「ステージング」されたままになります。

最初の要求が成功した場合、有効なトークンがあり、何も再作成せずに、作成したオブジェクトを何度でも取得できます。

トークンがデータストア内のオブジェクトのIDになれない理由はありません。最初のリクエスト中にオブジェクトを作成できます。 2番目のリクエストは、実際には「ステージ」フィールドを更新するだけです。

3
Travis Parks

サーバー発行の識別子

識別子を発行するのがサーバーである場合を扱う場合は、一時的なステージング状態でオブジェクトを作成します。 (これは本質的に非べき等の操作であるため、POSTを使用して実行する必要があります。)その後、クライアントは、ステージング状態からアクティブ/プリザーブ状態(PUTリソースのプロパティ、または適切なPOST)。

各クライアントは、ステージングされた状態のリソースのリストを何らかの方法で取得できる必要があり(他のリソースと混合される可能性があります)、まだステージングされている場合は作成したリソースを削除できる必要があります。しばらくアクティブでないステージングされたリソースを定期的に削除することもできます。

あるクライアントのステージングされたリソースを他のクライアントに公開する必要はありません。それらは、確認ステップの後にのみグローバルに存在する必要があります。

クライアント発行の識別子

別の方法は、クライアントが識別子を発行することです。これは主に、ファイル名がユーザーコードにとって重要であるため、ファイルストアのようなものをモデリングする場合に役立ちます。この場合、PUTを使用してリソースの作成を行うことができます。これは、すべてdem等に行うことができるためです。

この欠点は、クライアントがIDを作成できるため、クライアントが使用するIDをまったく制御できないことです。

2
Donal Fellows

この問題には別のバリエーションがあります。クライアントに一意のIDを生成させることは、この問題を解決するようお客様にお願いしていることを示しています。公開されたAPIがあり、これらのAPIと統合するクライアントが何百もある環境を考えてみましょう。実際には、クライアントコードと一意性の実装の正確さを制御することはできません。したがって、リクエストが重複しているかどうかを理解するためのインテリジェンスを持つ方がおそらく良いでしょう。ここでの簡単なアプローチの1つは、ユーザー入力からの属性に基づいてすべての要求のチェックサムを計算して保存し、時間のしきい値(x分)を定義し、同じクライアントからのすべての新しい要求を過去x分で受信した要求と比較することです。チェックサムが一致する場合、リクエストが重複している可能性があり、クライアントがこれを解決するためのチャレンジメカニズムを追加します。クライアントがx mins以内に同じパラメーターで2つの異なるリクエストを作成する場合、一意のリクエストIDで送信される場合でも、これが意図的なものであることを確認する価値があります。このアプローチはすべてのユースケースに適しているわけではありませんが、2回目の呼び出しを実行することによるビジネスへの影響が大きく、顧客にコストがかかる可能性がある場合に役立つと思います。中間層が失敗したリクエストの再試行に終わる支払い処理エンジンの状況を考えてみてくださいOR顧客がダブルクリックして、クライアント層で2つのリクエストを送信します。

0
Neeraj

設計

  • 自動(手動のブラックリストを維持する必要なし)
  • メモリ最適化
  • ディスク最適化

アルゴリズム[解決策1]

  1. RESTはUUIDで到着します
  2. Webサーバーは、UUIDがメモリキャッシュブラックリストテーブルにあるかどうかを確認します(ある場合は、409と答えます)
  3. サーバーは要求をDBに書き込みます(ETSによってフィルターされなかった場合)
  4. DBは、書き込み前にUUIDが繰り返されているかどうかをチェックします
  5. はいの場合、サーバーに対して409と回答し、メモリキャッシュとディスクにブラックリストを作成します
  6. DBへの書き込みを繰り返し、200と答えない場合

アルゴリズム[解決策2]

  1. RESTはUUIDで到着します
  2. メモリキャッシュテーブルにUUIDを保存します(30日間有効)
  3. Webサーバーは、UUIDがメモリキャッシュブラックリストテーブルにあるかどうかを確認します[HTTP 409を返します]
  4. サーバーがリクエストをDBに書き込む[HTTP 200を返す]

ソリューション2では、メモリキャッシュブラックリストを作成するためのしきい値はメモリ内でのみ作成されるため、DBの重複はチェックされません。 「複製」の定義は、「一定期間内に発生する要求」です。また、ディスク上のメモリキャッシュテーブルも複製するため、サーバーを起動する前にテーブルを埋めます。

ソリューション1では、書き込み前にディスクを1回だけチェックインし、重複している場合、次のラウンドトリップはメモリキャッシュによって処理されるため、重複はありません。このソリューションはBig Queryに適しています。なぜなら、リクエストにはim等がないからです。しかし、最適化もされていません。

POSTリソースが既に存在する場合)のHTTP応答コード

0
Henry H.