34

私の現在のアプローチが理にかなっているのか、それとももっと良い方法があるのか​​ 疑問に思っています。

新しいオブジェクトを作成し、サーバーにそれらのオブジェクトに ID を割り当てさせたい状況が複数あります。POST リクエストを送信するのが最も適切な方法のようです。ただし、POST はべき等ではないため、リクエストが失われ、再度送信すると 2 番目のオブジェクトが作成される可能性があります。また、API はモバイル ネットワーク経由でアクセスされることが多いため、リクエストが失われることはよくあることです。

その結果、すべてを 2 段階のプロセスに分割することにしました。

  1. 最初に POST リクエストを送信して新しいオブジェクトを作成し、新しいオブジェクトの URI を Location ヘッダーに返します。

  2. 2 番目に、指定された Location に対してべき等 PUT 要求を実行して、新しいオブジェクトにデータを入力します。新しいオブジェクトが 24 時間以内に入力されない場合、サーバーは何らかのバッチ ジョブを使用してそのオブジェクトを削除する場合があります。

それは合理的に聞こえますか、それともより良いアプローチがありますか?

4

6 に答える 6

39

PUT 作成に対する POST 作成の唯一の利点は、ID のサーバー生成です。冪等性の欠如に値するとは思いません (そして、重複または空のオブジェクトを削除する必要があります)。

代わりに、URLにUUIDを含む PUT を使用します。UUID ジェネレーターのおかげで、クライアント側で生成した ID がサーバー側で一意になることはほぼ確実です。

于 2012-12-28T13:06:52.283 に答える
17

それはすべて依存します。まず、URI、リソース、および表現についてもっと話し、オブジェクトについて心配する必要はありません。

POST メソッドは、べき等でないリクエスト、または副作用のあるリクエスト用に設計されていますが、べき等のリクエストにも使用できます

/some_collection/ へのフォーム データの POST 時

normalize the natural key of your data (Eg. "lowercase" the Title field for a blog post)
calculate a suitable hash value (Eg. simplest case is your normalized field value)
lookup resource by hash value
if none then
    generate a server identity, create resource
        Respond =>  "201 Created", "Location": "/some_collection/<new_id>" 
if found but no updates should be carried out due to app logic
        Respond => 302 Found/Moved Temporarily or 303 See Other 
        (client will need to GET that resource which might include fields required for updates, like version_numbers)
if found but updates may occur
   Respond => 307 Moved Temporarily, Location: /some_collection/<id> 
   (like a 302, but the client should use original http method and might do automatically) 

適切なハッシュ関数は、いくつかの連結されたフィールドと同じくらい単純かもしれません。または、大きなフィールドまたは値の場合は、切り捨てられた md5 関数を使用できます。詳細については、[ハッシュ関数] を参照してください2

私はあなたを仮定しました:

  • ハッシュ値とは異なる ID 値が必要
  • ID に使用されるデータ フィールドは変更できません
于 2013-01-02T12:43:56.890 に答える
5

サーバー、アプリケーション、専用の要求応答で ID を生成する方法は非常に優れています。一意性は非常に重要ですが、求婚者のようなクライアントは、成功するまで、または受け入れても構わないと思って失敗するまで、要求を繰り返し続けます (可能性は低いです)。したがって、どこかから一意性を取得する必要があり、選択肢は 2 つしかありません。Aurélienが提案するGUIDを持つクライアント、またはあなたが提案するサーバーのいずれかです。私はたまたまサーバーオプションが好きです。リレーショナル DB のシード列は、衝突のリスクがなく、すぐに利用できる一意性のソースです。2000 年頃、「Simple Reliable Messaging with HTTP」などと呼ばれるこのソリューションを提唱する記事を読んだので、これは実際の問題に対する確立されたアプローチです。

REST の記事を読んでいると、10 代の若者たちがエルヴィスの屋敷を相続したと考えても仕方ありません。彼らは家具をどのように再配置するかについて興奮して話し合っており、家から何かを持ってくる必要があるかもしれないという考えにヒステリックです. POST の使用が推奨されます。これは、冪等でないリクエストに関する問題を提起することなく存在するためです。

実際には、API へのすべての安全でないリクエストが idempotent であることを確認したい可能性があります。ID の生成は安価であり、未使用の ID は簡単に破棄されます。REST への同意として、POST を使用して新しい ID を取得することを忘れないでください。これにより、キャッシュされず、あちこちで繰り返されません。

べき等が何を意味するかについての不毛な議論に関して、私はそれがすべてである必要があると言います。連続するリクエストは追加の効果を生成してはならず、最初に処理されたリクエストと同じレスポンスを受け取る必要があります。これを実装するには、すべてのサーバー応答を保存して再生できるようにする必要があります。ID は、リソースだけでなくアクションを識別します。あなたはエルヴィスの邸宅から追い出されますが、防爆 API を手に入れることができます。

于 2016-02-10T16:23:03.750 に答える
3

使用するHTTPメソッドに関係なく、一時的に(一部のリクエストチェックシステムの一部として)、または永続的なサーバーIDとして、クライアント側で一意の識別子を生成せずにべき等リクエストを行うことは理論的に不可能です。HTTPリクエストが失われた場合でも、重複は作成されません。ただし、リクエストがサーバーに到達するのに成功する可能性があるという懸念がありますが、応答によってクライアントに返されることはありません。

エンドクライアントが重複を簡単に削除でき、それらが固有のデータ競合を引き起こさない場合、アドホックな重複防止システムを開発するのに十分な取引ではない可能性があります。リクエストにPOSTを使用し、HTTPヘッダーで201ステータスを返し、レスポンスの本文でサーバーが生成した一意のIDをクライアントに送り返します。重複が頻繁に発生することを示すデータがある場合、または重複が重大な問題を引き起こす場合は、PUTを使用して、クライアント側で一意のIDを作成します。クライアントが作成したIDをデータベースIDとして使用します。サーバー上に追加の一意のIDを作成する利点はありません。

于 2012-12-31T19:26:08.443 に答える
3

しかし、今、失われる可能性のある 2 つの要求がありますか? また、POST を繰り返して、別のリソース インスタンスを作成することもできます。考えすぎないでください。バッチプロセスで重複を探すだけです。おそらく、リソースの「アクセス」カウント統計をいくつか作成して、放棄された投稿の結果であるだまされた候補を確認してください。

別のアプローチ: 着信 POST をいくつかのログに対してスクリーニングして、それが繰り返しかどうかを確認します。簡単に見つけられるはずです: リクエストの本文の内容がちょうど x 時間前のリクエストの内容と同じである場合、それは繰り返しと考えてください。また、発信元 IP、同じ認証などの追加パラメータを確認できます...

于 2012-12-21T14:52:06.813 に答える
2

作成と更新のリクエストを1つのリクエスト(アップサート)にまとめることもできると思います。新しいリソースを作成するために、クライアントは、たとえば/factory-url-nameにある「ファクトリ」リソースをPOSTします。次に、サーバーは新しいリソースのURIを返します。

于 2012-12-21T14:37:07.993 に答える