14

RESTful SOAで、AJAXを介してPOSTリクエストを発行したが、リクエストがタイムアウトする前に応答を受け取らなかったとします。さらに、リクエストの再送信は有害であると想定します。POSTはべき等ではありません。たとえば、銀行振込を投稿している場合があります。応答がない場合は、サーバーが要求を処理したかどうかわかりません。

クライアント側とサービス側を制御できると仮定して、これに対処するためのベストプラクティスは何ですか?

私の最初の考えは、各POSTリクエストにナンス(つまり、疑似ID、ある種の一意の識別子)を含めることです。たとえば、If-None-Matchヘッダーの値などです。このアプローチでは、クライアント側はプログラムで同じ疑似IDを使用してタイムアウトした要求を再発行でき、サーバーは繰り返し値が含まれている場合にそれを拒否できます。

4

1 に答える 1

19

これを解決するために私が聞いた多くの方法があります

  1. 現在の状態を取得します。

    POST が失敗した場合、クライアントが同じリソースに対して GET を発行し、返されたデータに基づいて、POST が成功したか失敗したかを判断できるように、サービスを設計します。

    このアプローチの問題は、POST がコレクション内に新しいアイテムを作成する場合に、クライアントが投稿が成功したかどうかを判断するのが難しい場合があることです (つまり、私の投稿がそのアイテムを追加したのか、それとも他の人の投稿が追加したのか)。

  2. イフマッチ

    ヘッダーを使用してIf-Match、POST が繰り返されないようにします。たとえば、POST がアイテムをコレクションに追加していて、コレクションにETag現在737060cd8c284d8af7ad3082f209582d. If-Matchofが POST で使用されている場合737060cd8c284d8af7ad3082f209582d、POST は、コレクションのETagがまだ737060cd8c284d8af7ad3082f209582dである場合にのみ成功します。これにより、アイテムが追加さETagれ、コレクションの新しい結果が得られます。この段階で POST を繰り返すと、単に返され412 Precondition Failedます。

    このアプローチの問題は、 を取得したときに、412 Precondition Failed自分の POST がコレクションを変更したのか、それとも他の誰かのコレクションを変更したのかがわからないことです。

  3. POST してから PUT

    POST からのデータを保持しないようにサービスを設計します。代わりに、POST は POST コンテンツを含む一時的なリソースを作成します。これは「保留中」状態です。この一時的なリソースは、PUT で「コミット」されます。このアプローチでは、POST がタイムアウトしたかどうかは気にせず、POST を再度リクエストするだけで、一時的なリソースを取得できます。リソースをコミットする PUT がタイムアウトしても、PUT はべき等であるため、気にする必要はありません。

    このアプローチの唯一の本当の欠点は、一時的なリソースを管理するために必要な余分な作業と、クライアントで必要な余分な労力です。

    アップデート

  4. ノンス

    リクエストで nonce (メッセージ ID、トランザクション ID、リクエスト ID、相関 ID) を使用することは、この問題を解決するための一般的なアプローチです。ただし、スケーラビリティの問題が発生する可能性があります。以前の nonce を使用するすべての POST を拒否することをコミットする場合は、既存の POST レコードをスキャンして、その nonce が以前に使用されたかどうかを判断する必要があります。数千の POST しかない場合は問題ありませんが、数百万の POST がある場合は問題になる可能性があります (特に、クエリが高速な方法で nonce を保存していない場合)。

    これは、特定の時間枠 (たとえば、過去 24 時間) 内に以前の nonce を使用するすべての POST を拒否するコミットメントを減らすことで軽減できますが、最初の POST がタイムアウトし、クライアントがその時間枠で切断された場合、クライアントは元の状態に戻ります。同じ古い立場で、最初の POST が成功したかどうかがわからず、再投稿する必要があるかどうかを判断する方法がありません。

于 2012-12-12T11:54:46.740 に答える