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


47

最終的な処理のために長時間実行されるタスクをキューに入れることをサポートする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"
}

次に、クライアント側で、リクエストが完了したかどうかを判断するためswitchに(ため息をつきます)response.data.status

これは私がやるべきことですか?または、より良い代替手段はありますか?これは私にとってWeb 1.0だと感じています。


1
その目的のために1xxコードが正確に作成されていませんか?
アンディ

@Andy私は102を見ていましたが、それはWebDAVのものです。それを超えて、いや...彼らは主に輸送中の通信のためのものです。Webソケットなどへの切り替えに役立ちます。
マシューハウゲン

どのような遅延が発生していますか?10秒?それとも6時間?遅延が短く、通常は同じブラウザーアクセス内である場合、定期的なポーリングではなく、長いポーリングまたはWebソケットを実行する場合があります。
GrandmasterB

@GrandmasterB潜在的には数時間です。私はジョブ処理自体に責任を負いませんので、本当に良い見積もりはありませんが、しばらくはかかります。それ以外の場合は、最初のPOSTリクエストを開いたままにしておきます。長いポーリングまたはWebソケットの主な問題は、ユーザーがブラウザーを閉じて戻ってくる可能性があることです。そのときにそれらを再び開くことができます(そしてそれは私がしていることです)が、それらのソケットを開く前に呼び出す単一のAPIを持っていることはきれいです。
マシューハウゲン

回答:


48

HTTP 202が受け入れられました(HTTP / 1.1)

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

要求は処理のために受け入れられましたが、処理は完了していません。

HTTP 102処理(WebDAV)

RFC 2518では、次の使用を推奨していHTTP 102 Processingます。

102(処理中)ステータスコードは、サーバーが完全な要求を受け入れたがまだ完了していないことをクライアントに通知するために使用される暫定応答です。

ただし、警告があります。

サーバーは、要求が完了した後に最終応答を送信する必要があります。

最後の文をどう解釈するかわかりません。サーバーは処理中に何も送信せず、完了にのみ応答する必要がありますか?または、処理が終了したときにのみ応答を強制的に終了しますか?これは、進行状況を報告する場合に役立ちます。HTTP 102を送信し、バイトごとに(または行ごとに)応答をフラッシュします。

たとえば、長くても線形のプロセスの場合、100文字のドットを送信して、各文字の後にフラッシュできます。クライアント側(JavaScriptアプリケーションなど)が正確に100文字を想定していることを知っている場合、ユーザーに表示する進行状況バーと一致させることができます。

別の例は、いくつかの非線形ステップで構成されるプロセスに関するものです。各ステップの後、最終的にユーザーに表示されるログメッセージをフラッシュして、エンドユーザーがプロセスの進行状況を把握できるようにすることができます。

プログレッシブフラッシュの問題

この手法にはメリットがありますが、お勧めしません。その理由の1つは、接続を強制的に開いたままにすることです。これは、サービスの可用性の点で損害を与える可能性があり、適切に拡張できません。

より良いアプローチは、応答してHTTP 202 Accepted、ユーザーが後であなたに戻って処理が終了したかどうかを判断させることです(たとえば、プロセスまで/process/resultHTTP 404 Not FoundまたはHTTP 409 Conflictで応答するような特定のURIを繰り返し呼び出すことによって)終了し、結果の準備ができました)、またはメッセージキューサービス()またはWebSocketsを介して、たとえばクライアントをコールバックできる場合、処理が完了したときにユーザーに通知します。

実用例

ビデオを変換するWebサービスを想像してください。エントリポイントは次のとおりです。

POST /video/convert

HTTPリクエストからビデオファイルを取得し、それを使用して魔法をかけます。魔法はCPUに負荷がかかるため、リクエストの転送中にリアルタイムで実行できないと想像してください。これは、ファイルが転送されると、サーバーがHTTP 202 AcceptedJSONコンテンツで応答することを意味します。将来のどこかで準備が整い、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タスクをキューに入れます。一度だけ呼び出す必要があります。もう一度呼び出すと、追加のタスクがキューに入れられます。
  • GET /video/download/123操作の結果に関するものです。リソースはビデオです。ここでは、処理(要求の前に、要求とは独立して実際の結果を準備するために内部で行われた処理)は無関係です。1回または数回呼び出すことができます。
  • GET /video/status/123処理自体に関係します。何もキューに入れません。結果のビデオは気にしません。リソースは、処理自体です。1回または数回呼び出すことができます。

1
GETしかし、202はaに対応して意味をなしますか?それは確かにinitialの正しい選択POSTです。だからこそ私はそれを使用しています。しかしGET、特定のリクエストから何も受け入れなかったときに「受け入れられた」と言うのは意味的に疑わしいようです。
マシューハウゲン

2
@MainMa先ほど言ったようにPOST、ジョブをキューに入れ、次にGETクライアントがセッションを閉じた後に結果を待ちます。404も私が検討したものですが、リクエスト見つかったために完了していないため、間違っているようです。それは、キューに入れられたジョブが見つからなかったことを私に示します。これは非常に異なる状況です。
マシュー

1
@MatthewHaugen:あなたがやる時にGET一部を、としてそれについて考えていない不完全な要求が、要求として操作の結果を取得します。私はビデオを変換するように指示している場合例えば、それはのために要求して、それを行うには、あなたに5分かかり変換されたビデオ 2分後にすべき映像がまだ単純ではないため、HTTP 404につながります。一方、操作自体の進行を要求すると、おそらく変換されたバイト数、速度などを含むHTTP 200が生成されます。
ArseniMourzenko

5
まだ利用できないリソースのHTTPステータスコードは、リソースが存在しない場合、404応答ではなく、409競合応答(「リソースの現在の状態と競合するため、要求を完了できませんでした。」)を返すことを示唆しています生成されているため、存在しません。
ブライアン

1
@ブライアンあなたのコメントは、この質問に対する合理的な答えになるでしょう。その後、「[t]彼のコードは、ユーザーが競合を解決してリクエストを再送信できることが予想される状況でのみ許可されます」と応答しますが、これは厳密には真実ではありませんが、 「見つかりません」よりも間違いが少ない。私の一部は、Retry-Afterヘッダーが固定された409に傾いています。唯一の問題は、GETで409を返すのがおかしいように見えることですが、私はそのおかしさで生きることができます。将来定義される可能性は低いでしょう。
マシューハウゲン

5

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

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

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

HTTPステータスコードは、そのリソースの詳細に関係なく、処理対象のリソースのクライアントとサーバー間の状態転送に対応していることに注意してください。GETリソースが現在の状態にあるリソースの表現をサーバーに要求しているとき、それは鳥の絵かもしれませんし、Word文書かもしれませんし、現在の外部tempかもしれません。HTTPプロトコルは気にしません。HTTPステータスコードは、そのリクエストの結果に対応しています。DID POSTクライアントからサーバはその後、それをクライアントが表示できるURLを与えたサーバーに、サーバー移転リソースに?はい?それが201 Created応答です。

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

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

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

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

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


「クライアントからサーバーへのPOSTはリソースをサーバーに転送し、サーバーはクライアントが表示できるURLを提供しましたか?はい?それは201 Created応答です。」202 Acceptedは、サーバーがリソースを処理するためにすぐに動作できない場合、これに対する応答としても受け入れられます。これがOPの動作です。
アンディ

1
問題は、サーバーがすぐに動作していることです。URLを含むリソースをすぐに作成します。リソースの状態が「Pending」(または何か)であるだけです。それはビジネスドメインの状態です。HTTPプロトコルに関する限り、サーバーはリソースを作成するとすぐに動作し、クライアントにリソースのURLを提供しました。そのリソースを取得できます。POST要求自体は保留されていません。これは、2つの異なる概念ドメインを別々に保つことによって意味します。クライアントが火災を送信していて、何時間も実行されなかったPOST要求を忘れた場合、202が適用されます。
コーマックマルホール

URLが存在するかどうかは誰も気にしませんが、リソースはまだ処理中であるため、リソースが表すデータを取得できません。動画の取得に使用できるようになるまで、URLを作成しないでください。
アンディ

リソースが作成され、「保留中」状態になります。それ自体が関連データです。将来のある時点で、サーバーはリソースの状態を「完了」(または「失敗」)に変更する可能性がありますが、これは「リソースの作成」というHTTPドメイン固有のタスクとは異なる概念です。保留は「リクエスト」リソースの完全に有効な状態になる可能性があり、クライアントは明らかにサーバーがその状態でリソースを作成したことを知りたいと思っています。状態が変化した場合。
コーマックマルホール

4

このブログからの提案は合理的だと思いました:RESTと長時間実行ジョブ

要約する:

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

2

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

w3仕様から:

10.4.10 409競合

リソースの現在の状態と競合するため、要求を完了できませんでした。このコードは、ユーザーが競合を解決してリクエストを再送信できることが予想される場合にのみ許可されます。応答本文には十分な情報を含める必要があります

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

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

409コードは「ユーザーが競合を解決してリクエストを再送信できる可能性があると予想される状況でのみ許可されている」ため、これはやや厄介です。応答本文には、「このリソースは現在生成中です。[TIME]に開始され、[TIME]に完了すると推定されます。」などのメッセージ(おそらく、APIの残りの部分と一致する応答形式)を含めることをお勧めしますあとでもう一度試してみてください。"

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


409が実際に何を意味するのか、これはputに対応するストレッチのようです。
アンディ

@アンディ:本当ですが、他のすべての選択肢もそうです。たとえば、202は実際には、処理の結果を要求した要求ではなく、処理を開始した要求に対する応答であることを意味します。実際には、リソースが見つからなかったため、最も仕様に準拠した応答は404です(まだ存在していなかったため)。404応答内でAPIが関連するapiデータを提供するのを止めるものは何もありません。4xx / 5xxのレスポンスは消費するのが面倒です。一部の言語では、異なるステータスコードを提供するだけでなく、例外が発生します。
ブライアン

2
いいえ、特にMainMaの回答の最後の数段落。リクエストのステータスを確認し、ビデオ自体を取得するには、エンドポイントを分離します。ステータスはビデオと同じリソースではないため、単独でアドレス指定できる必要があります。
アンディ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.