私は、最終的に処理するための長時間実行タスクのキューイングをサポートするRESTful APIを構築しています。
このAPIの一般的なワークフローは次のとおりです。
/results/{request_id}
)私の問題はステップ6にあります。ユーザーがページにアクセスするたびに、API(GET /api/results/{request_id}
)。理想的には、タスクは今までに完了していて、タスクの結果とともに200 OKを返します。
しかし、ユーザーは強引であり、結果がまだ処理を終えていない場合、私は多くの熱狂的な更新を期待しています。
ステータスコードがそれを示すための私の最良のオプションは何ですか:
単一のコードですべてをやり取りすることは期待していませんが、クライアントにコンテンツを期待させる代わりに、メタデータを渡すことができるものを望んでいます。
202を返すのは理にかなっている可能性があります。ここでは他の意味がないためです。これはGET
リクエストなので、何も「受け入れられない」可能性があります。それは合理的な選択でしょうか?
これらすべての明白な代替策-これは機能しますが、ステータスコードの1つの目的を無効にします-常にメタデータを含めることです。
200 OK
{
status: "complete",
data: {
foo: "123"
}
}
...または...
200 OK
{
status: "pending"
}
次に、クライアント側で、私は(ため息)switch
をresponse.data.status
リクエストが完了したかどうかを判断します。
これは私がやるべきことですか?または、より良い代替案はありますか?これはちょうど私にとってWeb 1.0のように感じます。
HTTP 202 Accepted
ステータスを探しています。 RFC 2616 を参照してください。
リクエストは処理のために受け入れられましたが、処理は完了していません。
RFC 2518 はHTTP 102 Processing
の使用を提案します:
102(処理中)ステータスコードは、サーバーが完全な要求を受け入れたがまだ完了していないことをクライアントに通知するために使用される暫定的な応答です。
ただし、注意点があります。
サーバーは、要求が完了した後に最終応答を送信する必要があります。
最後の文をどう解釈すればよいかわかりません。サーバーは処理中に何かを送信することを避け、完了後にのみ応答しますか?または、処理が終了したときにのみ応答を強制的にendに強制しますか?これは、進捗状況を報告する場合に役立ちます。 HTTP 102を送信し、バイト単位(または行単位)で応答をフラッシュします。
たとえば、長くて線形のプロセスの場合、100文字のドットを送信し、各文字の後にフラッシュすることができます。クライアント側(JavaScriptアプリケーションなど)は、正確に100文字を期待する必要があるとわかっている場合、プログレスバーと一致させてユーザーに表示できます。
別の例は、いくつかの非線形ステップで構成されるプロセスに関するものです。各ステップの後で、最終的にユーザーに表示されるログメッセージをフラッシュして、エンドユーザーがプロセスの進行状況を知ることができるようにすることができます。
このテクニックにはメリットがありますが、お勧めしません。その理由の1つは、接続を強制的に開いたままにすることです。これにより、サービスの可用性の点で問題があり、拡張性が低下します。
より良いアプローチは、HTTP 202 Accepted
で応答し、後でユーザーに戻って処理が終了したかどうかを判断できるようにすることです(たとえば、HTTPで応答する/process/result
などの特定のURIを繰り返し呼び出すことにより) 404 Not Foundまたは HTTP 409 Conflict プロセスが終了して結果が準備できるまで)、またはメッセージキューなどを介してクライアントにコールバックできる場合は、処理が完了したときにユーザーに通知するservice( example )またはWebSockets。
ビデオを変換するWebサービスを想像してみてください。エントリポイントは次のとおりです。
POST /video/convert
これは、HTTPリクエストからビデオファイルを取得し、それに魔法をかけます。マジックがCPUを集中的に使用するため、リクエストの転送中にリアルタイムで実行できないと想像してみてください。これは、ファイルが転送されると、サーバーがJSONコンテンツを含むHTTP 202 Accepted
で応答することを意味します。 ID 123を通じて利用できるようになる予定です。」
クライアントは、メッセージキューをサブスクライブして、処理の終了時に通知を受けることができます。完了すると、クライアントは次の場所に移動して処理済みのビデオをダウンロードできます。
GET /video/download/123
これはHTTP 200
につながります。
クライアントが通知を受信する前にこのURIをクエリするとどうなりますか?まあ、実際にはまだビデオが存在しないので、サーバーはHTTP 404
で応答します。現在準備中かもしれません。それは決して要求されないかもしれません。過去に存在し、後で削除される可能性があります。重要なのは、結果のビデオが利用できないことです。
では、クライアントが最終的なビデオだけでなく進行状況(メッセージキューサービスや同様のメカニズムがない場合はさらに重要になります)にも関心があるとしたらどうでしょうか。
この場合、別のエンドポイントを使用できます。
GET /video/status/123
これは次のような応答になります。
HTTP 200
{
"id": 123,
"status": "queued",
"priority": 2,
"progress-percent": 0,
"submitted-utc-time": "2016-04-19T13:59:22"
}
リクエストを何度も行うと、次の状態になるまで進行状況が表示されます。
HTTP 200
{
"id": 123,
"status": "done",
"progress-percent": 100,
"submitted-utc-time": "2016-04-19T13:59:22"
}
これら3つのタイプのリクエストを区別することが重要です。
POST /video/convert
はタスクをキューに入れます。これは1回だけ呼び出す必要があります。もう一度呼び出すと、追加のタスクがキューに入れられます。GET /video/download/123
は、操作の結果に関係します。resourceはビデオです。処理(つまり、要求前に実際の結果を準備する準備する(---)ために内部で行われた処理)は、ここでは関係ありません。 1回または複数回呼び出すことができます。GET /video/status/123
は、処理自体に関係します。何もキューに入れません。結果のビデオは関係ありません。 resourceは処理そのものです。 1回または複数回呼び出すことができます。これらすべての明白な代替策-これは機能しますが、ステータスコードの1つの目的を無効にします-常にメタデータを含めることです。
これが正しい方法です。リソースがドメイン固有のログ(別名ビジネスロジック)に関して存在する状態は、リソースの表現のコンテンツタイプの問題です。
ここでは、実際に異なる2つの異なる概念が統合されています。 1つは、リソースのクライアントとサーバー間の状態転送のステータスであり、もう1つは、ビジネスドメインがそのリソースのさまざまな状態を理解するコンテキストでのリソース自体の状態です。 後者はHTTPステータスコードとは関係ありません。
HTTPステータスコードは、処理されるリソースのクライアントとサーバー間の状態転送に対応し、そのリソースの詳細とは独立していることに注意してください。 GET
リソースをクライアントがサーバーに、現在の状態のリソースの表現を要求しています。これは鳥の写真の場合もあれば、Word文書の場合もあります。温度外の電流。 HTTPプロトコルは関係ありません。 HTTPステータスコードは、そのリクエストの結果に対応しています。クライアントからサーバーへのPOST
はリソースをサーバーに転送しましたか。サーバーは、クライアントが表示できるURLをサーバーに提供しましたか?はい?次に、それは201 Created
応答です。
リソースは、現在「レビュー対象」状態にある航空会社の予約である可能性があります。または、「承認済み」状態の製品発注書である可能性があります。これらの状態はドメイン固有であり、HTTPプロトコルの目的ではありません。 HTTPプロトコルは、クライアントとサーバー間のリソースの転送を処理します。
RESTおよびHTTPのポイントは、プロトコルがリソースの詳細に関与しないことです。これは意図的なものであり、ドメイン固有の問題に関与しないため、ドメイン固有の問題について何も知らなくても使用できます。HTTPステータスコードが各コンテキスト(航空券予約システム、画像処理システム、ビデオセキュリティシステムなど)で何を意味するかを再解釈する必要はありません。
ドメイン固有のものは、クライアントとサーバーがリソースのContent Type
に基づいてそれらの間で理解するためのものです。 HTTPプロトコルはこれにとらわれません。
リクエストリソースが状態を変更したことをクライアントがどのように把握するかについては、クライアントで制御を維持し、切断されていない接続を想定しないため、ポーリングが最善の策です。特に、状態が変化するまで数時間かかる可能性がある場合。 RESTで地獄と言ったとしても、接続を開いたままにして、何時間も接続を開いたままにし、何も問題がないと想定することは悪い考えです。ユーザーがクライアントまたはネットワークが停止します。粒度が数時間の場合、クライアントは、リクエストが「保留」から「完了」に変わるまで、数分ごとに状態をリクエストできます。
物事を明確にするのに役立つことを願っています
私はこのブログからの提案が妥当であることがわかりました: RESTおよび長期実行ジョブ 。
要約する:
リソースのHTTPステータスコードはまだ使用できません は、リソースが生成中であるためにリソースが存在しない場合に、404応答ではなく409競合応答を返すことを提案します。
w3 spec から:
10.4.10 409コンフリクト
リソースの現在の状態と競合しているため、要求を完了できませんでした。このコードは、ユーザーが競合を解決してリクエストを再送信できると予想される状況でのみ許可されます。レスポンスボディは十分に含める必要があります
ユーザーが競合の原因を認識するための情報。理想的には、応答エンティティには、ユーザーまたはユーザーエージェントが問題を修正するのに十分な情報が含まれます。ただし、それは不可能である場合があり、必須ではありません。
競合は、PUTリクエストへの応答で発生する可能性が最も高いです。たとえば、バージョニングが使用されていて、PUTされているエンティティにリソースへの変更が含まれており、それが以前の(サードパーティ)リクエストによる変更と競合する場合、サーバーは409レスポンスを使用して、リクエストを完了できないことを示します。 。この場合、応答エンティティには、応答のContent-Typeで定義された形式で2つのバージョンの違いのリストが含まれている可能性があります。
409コードは「ユーザーが競合を解決してリクエストを再送信できると予想される状況でのみ許可される」ため、これは少し厄介です。応答の本文には、「このリソースは現在生成中です。[TIME]に開始され、[TIME]に完了すると推定されます。あとでもう一度試してみてください。"
リソースを要求しているユーザーがそのリソースの生成を開始したユーザーでもある可能性が高い場合にのみ、409のアプローチを提案することに注意してください。リソースの生成に関与していないユーザーは、404エラーで混乱が少なくなります。