6

POST を使用して新しいリソースを作成するときに重複リソースが誤って作成されるのを防ぐためのベスト プラクティスを探していました。これは、リソースがサーバーによって名前が付けられるため、PUT を使用できない場合です。私が構築している API はモバイル クライアントによって使用されます。私が懸念している状況は、クライアントが POST 要求を送信した後、応答を取得する前に切断される場合です。私はこの質問を見つけましたが、条件付き POST の使用について言及されていなかったため、私の質問です。

条件付き PUT を使用してリソースを変更するのと同じように、親リソースに条件付き POST を実行することは、この問題に対する合理的な解決策ですか? そうでない場合、なぜですか?

クライアント/サーバーのやり取りは、条件付き PUT の場合と同じです。

  1. クライアントは、現在の状態を反映する ETag を含む親リソースを取得します (これには、下位リソースが含まれます)。

  2. クライアントは、親リソース (If-Match ヘッダーに親の ETag 値を含む) に対して条件付き POST を実行して、新しいリソースを作成します。

  3. クライアントはサーバーの応答を得る前に切断されるため、成功したかどうかわかりません。

  4. 後で再接続すると、クライアントは同じ条件付き POST リクエストを再送信します。

  5. 以前の要求がサーバーに到達しなかったためにサーバーがリソースを作成して 201 で応答するか、以前の要求がサーバーに到達したためにサーバーが 412 で応答し、重複したリソースは作成されません。

4

3 に答える 3

2

Your solution is clever, but less than ideal. Your client may never get his 201 confirmation, and will have to interpret the 412 error as success.

REST afficianados often suggest you create the resource with an empty POST, then, once the client has the id of the newly created resource, he can do an "idempotent" update to fill it. This is nice, but you will likely need to make DB columns nullable that wouldn't otherwise be, and your updates are only idempotent if no-one else is trying to update at the same time.

According to ME, HTTP is flaky. Requests timeout, browser windows get closed, connections get reset, trains go into tunnels with mobile users aboard. There's a simple, robust pattern for dealing with this. Unsafe actions should always be uniquely identified, and servers should store, and be able to repeat if necessary, the response to any unsafe request. This is not HTTP caching, where a request may be served from cache but the cache may be flushed for whatever reason. This is a guarantee by the server application that if an "action" request is seen a second time, the stored response will be repeated without anything else happening. If the action identity is to be generated by the server, then a request-response should be dedicated just to sending the id. If you implement this for one unsafe request, you might as well do it for all of them, and in so doing you will escape numerous thorny problems: successive update requests wiping out other users' changes, or hitting incompatible states ("order already submitted"), successive delete requests generating 404 errors.

I have a little google doc exploring the pattern more fully if you're interested.

于 2016-02-16T09:53:43.347 に答える
0

サーバーが使用することを選択した内部メカニズムを使用して、実際のリソースに基づいてサーバー上で重複検出を単純に実行しないのはなぜですか。

その方が安全です。

次に、URL を適切なリソースに返します (新しく作成されたかどうかに関係なく)。

親の ETag がサブ リソースの状態に基づいている場合、「重複リソース」を確認するための信頼できるメカニズムではありません。あなたが知っているのは、親が前回からどういうわけか「変わった」ということだけです。切断後に古い POST が処理されたことが原因であると、どうやってわかりますか? そのETagが変更された可能性があります。

これは基本的に楽観的なロック シナリオが実行されているものであり、別の問題に帰着します。リソースがすでに作成されている場合はどうなるでしょうか。それはエラーですか?それとも特徴?手入れする?リソースが既に存在する場合、サーバーによって暗黙のうちに無視される作成要求を送信するのは悪いことですか?

そして、それがすでに存在するが、「異なる」だけで十分な場合 (つまり、名前は一致するがアドレスが異なるなど)、それは重複していますか? それはアップデートですか?これは、既存のリソースを変更しようとした場合のエラーですか?

別の解決策は、2 回の旅行を行うことです。1 つはリクエストをステージングし、もう 1 つはそれをコミットします。リクエストが中断された場合は、戻ってきたときにリクエストのステータスを照会できます。コミットが完了しなかった場合は、再度コミットできます。もしそうなら、あなたは幸せであり、先に進むことができます.

通信がどれほど不安定で、この特定の操作がどれほど重要かによって、安全に行うためにフープを飛び越えたいかどうかに依存します.

于 2015-03-03T01:17:18.443 に答える