web-dev-qa-db-ja.com

「処理中」のHTTPステータスコード

私は、最終的に処理するための長時間実行タスクのキューイングをサポートするRESTful APIを構築しています。

このAPIの一般的なワークフローは次のとおりです。

  1. ユーザーがフォームに記入する
  2. クライアントがAPIにデータを投稿する
  3. APIが202 Acceptedを返す
  4. クライアントはユーザーをそのリクエストの一意のURL(/results/{request_id}
  5. 〜最終的に〜
  6. クライアントは再度URLにアクセスし、そのページの結果を確認します。

私の問題はステップ6にあります。ユーザーがページにアクセスするたびに、API(GET /api/results/{request_id})。理想的には、タスクは今までに完了していて、タスクの結果とともに200 OKを返します。

しかし、ユーザーは強引であり、結果がまだ処理を終えていない場合、私は多くの熱狂的な更新を期待しています。

ステータスコードがそれを示すための私の最良のオプションは何ですか:

  • このリクエストは存在します
  • まだ終わっていません
  • しかし、それも失敗していません。

単一のコードですべてをやり取りすることは期待していませんが、クライアントにコンテンツを期待させる代わりに、メタデータを渡すことができるものを望んでいます。

202を返すのは理にかなっている可能性があります。ここでは他の意味がないためです。これはGETリクエストなので、何も「受け入れられない」可能性があります。それは合理的な選択でしょうか?

これらすべての明白な代替策-これは機能しますが、ステータスコードの1つの目的を無効にします-常にメタデータを含めることです。

200 OK

{
    status: "complete",
    data: {
        foo: "123"
    }
}

...または...

200 OK

{
    status: "pending"
}

次に、クライアント側で、私は(ため息)switchresponse.data.statusリクエストが完了したかどうかを判断します。

これは私がやるべきことですか?または、より良い代替案はありますか?これはちょうど私にとってWeb 1.0のように感じます。

48
Matthew Haugen

HTTP 202受け入れ済み(HTTP/1.1)

HTTP 202 Acceptedステータスを探しています。 RFC 2616 を参照してください。

リクエストは処理のために受け入れられましたが、処理は完了していません。

HTTP 102処理(WebDAV)

RFC 2518HTTP 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回または複数回呼び出すことができます。
53

これらすべての明白な代替策-これは機能しますが、ステータスコードの1つの目的を無効にします-常にメタデータを含めることです。

これが正しい方法です。リソースがドメイン固有のログ(別名ビジネスロジック)に関して存在する状態は、リソースの表現のコンテンツタイプの問題です。

ここでは、実際に異なる2つの異なる概念が統合されています。 1つは、リソースのクライアントとサーバー間の状態転送のステータスであり、もう1つは、ビジネスドメインがそのリソースのさまざまな状態を理解するコンテキストでのリソース自体の状態です。 後者はHTTPステータスコードとは関係ありません。

HTTPステータスコードは、処理されるリソースのクライアントとサーバー間の状態転送に対応し、そのリソースの詳細とは独立していることに注意してください。 GETリソースをクライアントがサーバーに、現在の状態のリソースの表現を要求しています。これは鳥の写真の場合もあれば、Word文書の場合もあります。温度外の電流。 HTTPプロトコルは関係ありません。 HTTPステータスコードは、そのリクエストの結果に対応しています。クライアントからサーバーへのPOSTはリソースをサーバーに転送しましたか。サーバーは、クライアントが表示できるURLをサーバーに提供しましたか?はい?次に、それは201 Created応答です。

リソースは、現在「レビュー対象」状態にある航空会社の予約である可能性があります。または、「承認済み」状態の製品発注書である可能性があります。これらの状態はドメイン固有であり、HTTPプロトコルの目的ではありません。 HTTPプロトコルは、クライアントとサーバー間のリソースの転送を処理します。

RESTおよびHTTPのポイントは、プロトコルがリソースの詳細に関与しないことです。これは意図的なものであり、ドメイン固有の問題に関与しないため、ドメイン固有の問題について何も知らなくても使用できます。HTTPステータスコードが各コンテキスト(航空券予約システム、画像処理システム、ビデオセキュリティシステムなど)で何を意味するかを再解釈する必要はありません。

ドメイン固有のものは、クライアントとサーバーがリソースのContent Typeに基づいてそれらの間で理解するためのものです。 HTTPプロトコルはこれにとらわれません。

リクエストリソースが状態を変更したことをクライアントがどのように把握するかについては、クライアントで制御を維持し、切断されていない接続を想定しないため、ポーリングが最善の策です。特に、状態が変化するまで数時間かかる可能性がある場合。 RESTで地獄と言ったとしても、接続を開いたままにして、何時間も接続を開いたままにし、何も問題がないと想定することは悪い考えです。ユーザーがクライアントまたはネットワークが停止します。粒度が数時間の場合、クライアントは、リクエストが「保留」から「完了」に変わるまで、数分ごとに状態をリクエストできます。

物事を明確にするのに役立つことを願っています

6
Cormac Mulhall

私はこのブログからの提案が妥当であることがわかりました: RESTおよび長期実行ジョブ

要約する:

  1. サーバーはコード「202 Accepted」を返し、「Location」ヘッダーをURIに設定して、クライアントがステータスを確認できるようにします。 「/ queue/12345」。
  2. 処理が完了するまで、サーバーはステータスクエリに「200 OK」とジョブのステータスを示すいくつかの応答データで応答します。
  3. 処理が完了すると、サーバーはステータスクエリに応答し、「303 See Other」と「Location」を含むURIを最終結果に返します。
5
Xiangming Hu

リソースのHTTPステータスコードはまだ使用できません は、リソースが生成中であるためにリソースが存在しない場合に、404応答ではなく409競合応答を返すことを提案します。

w3 spec から:

10.4.10 409コンフリクト

リソースの現在の状態と競合しているため、要求を完了できませんでした。このコードは、ユーザーが競合を解決してリクエストを再送信できると予想される状況でのみ許可されます。レスポンスボディは十分に含める必要があります

ユーザーが競合の原因を認識するための情報。理想的には、応答エンティティには、ユーザーまたはユーザーエージェントが問題を修正するのに十分な情報が含まれます。ただし、それは不可能である場合があり、必須ではありません。

競合は、PUTリクエストへの応答で発生する可能性が最も高いです。たとえば、バージョニングが使用されていて、PUTされているエンティティにリソースへの変更が含まれており、それが以前の(サードパーティ)リクエストによる変更と競合する場合、サーバーは409レスポンスを使用して、リクエストを完了できないことを示します。 。この場合、応答エンティティには、応答のContent-Typeで定義された形式で2つのバージョンの違いのリストが含まれている可能性があります。

409コードは「ユーザーが競合を解決してリクエストを再送信できると予想される状況でのみ許可される」ため、これは少し厄介です。応答の本文には、「このリソースは現在生成中です。[TIME]に開始され、[TIME]に完了すると推定されます。あとでもう一度試してみてください。"

リソースを要求しているユーザーがそのリソースの生成を開始したユーザーでもある可能性が高い場合にのみ、409のアプローチを提案することに注意してください。リソースの生成に関与していないユーザーは、404エラーで混乱が少なくなります。

2
Brian