HTTPステータスコードを使用して、アプリケーションレベルのイベントを記述する必要がありますか


54

私が扱ったいくつかのサーバーは、クライアントが失敗と見なすべきリクエストに対してHTTP 200を返します。本文には「success:false」のようなものが含まれます。

これは、特に認証に失敗した場合、HTTPコードの適切な実装とは思えません。「4xx」は変更するまでリクエストを再度行うべきではないことを示し、「5xx」はリクエストが有効または無効であり、再試行できるが失敗したことを示すため、HTTPエラーコードを簡潔に要約しました。この場合、200:ログインに失敗した、または200:そのファイルが見つからなかった、または200:パラメータxが見つからない、間違いが間違っているようです。

一方、「4xx」はリクエストの構造的な問題を示すだけであるという議論が行われていることがわかりました。したがって、200を返すのは適切です。401不正ではなく、不正なユーザー/パスワードは、クライアントが要求を行うことを許可されているためです。この引数は、サーバーが要求を処理して決定を行うことができた場合、応答コードは200である必要があり、詳細については本文を確認するのはクライアント次第であると要約できます。

基本的に、これは好みの問題のようです。しかし、それは満足のいくものではないので、これらのパラダイムのいずれかがより正しい理由が誰かにあるなら、私は知りたいです。


9
success: falseはリクエストが失敗したことを意味し、あなたはそれを知っています。あなたの悪いユーザー名/パスワードのようなものは401でしょう。これはあいまいではありません。
ピート


4
これは、宗教戦争を引き起こす可能性のある質問の1つです。RESTful APIの場合、答えは明確ですが、HTTPがトランスポートレイヤーとして扱われる他の種類のAPIがあり、そのような場合、アプリケーションエラーがそのレイヤーに流出することはありません。
ロボット

5
どのHTTPステータスを返すか本当にわからないときは、418「私はティーポットです」で行くのはいつも魅力的です。
joshp

1
例は、複数の(バッチ化された)要求と応答です。バッチ処理は安らかなものではありません。しかし、実際の効率性の懸念から、優雅さの懸念よりもバッチ処理のサポートが必要になることがよくあります。
ルワン

回答:


35

興味深い質問。

基本的に、OSIレイヤーに類似した用語で物事を分類する正しい方法にこれを減らすことができます。HTTPは一般にアプリケーションレベルのプロトコルとして定義されており、実際にはHTTPは一般的なクライアント/サーバープロトコルです。

ただし、実際には、サーバーはほとんど常に中継デバイスであり、クライアントはコンテンツの解釈とレンダリングを行うWebブラウザーです。サーバーは、任意のものに物事を渡すだけで、そのアプリケーションはブラウザーが実行する責任があります。HTTPインタラクション自体(要求/応答フォーム、ステータスコードなど)は、ほとんどの場合、邪魔にならずに、任意のコンテンツを可能な限り効率的に要求、提供、レンダリングする方法の問題です。実際、ステータスコードとヘッダーの多くは、これらの目的のために設計されています。

アプリケーション固有のフローを処理するためにHTTPプロトコルを便乗しようとすると、次の2つのオプションのいずれかが残されるという問題があります。1)要求/応答ロジックをHTTPルールのサブセットにする必要があります。または2)特定のルールを再利用する必要がある場合、懸念事項の分離があいまいになる傾向があります。これは最初は見栄えが良くてきれいに見えるかもしれませんが、プロジェクトの発展に伴い後悔するような設計上の決定事項の1つだと思います。

したがって、プロトコルの分離について明示する方が良いと思います。HTTPサーバとWebブラウザが自分のことをやってみましょう、とアプリがやらせ自身のことを。アプリは要求を行うことができる必要があり、応答が必要です。また、要求方法、応答の解釈方法に関するロジックは、HTTPパースペクティブよりも複雑(または複雑ではない)にできます。

言及する価値があるこのアプローチのもう1つの利点は、一般的に言えば、アプリケーションが(論理的な観点から)基礎となるトランスポートプロトコルに依存しないことです。HTTP自体は過去に変更されており、現在ではSPDYに続いてHTTP 2が導入されています。アプリをHTTP機能プラグインとしてのみ表示する場合、新しいインフラストラクチャが引き継ぐとそこに行き詰まることがあります。


8
非常に洞察力に富んでいます。ここで最も強力な引数は、HTTPステータスコードとアプリの戻り値の間の(インピーダンス)不一致です。これは長期的には悪夢になります。さらに、トランスポート(HTTP)とペイロード(アプリデータ)の懸念の分離を強くサポートします。サービスエンドポイントのURLを誤って入力すると、404が表示されます。存在しないアイテムをサービスに要求すると、アプリ固有のメッセージが表示されます(問題の解決に使用できる追加情報が含まれる場合があります)。

2
あなたはURLの入力を間違えた場合は、あなたも右のサーバーで終わるかもしれないし、次に何が起こる可能性があります。
gnasher729

これは見事に微妙な外観です。HTTPが疑似トランスポート層になるという問題は、判断を下す際の本当の問題だと思います。nodejsサーバーをプロキシするnginxまたはapacheサーバーがあり、プロキシにこれらのコードを送信するためのルールが既にある場合、私はこの質問に自分でよく遭遇します。これらのケースのいくつかでは、nginxが「バックエンドダウン」として解釈する可能性があるため、エラーコードを送信しない設計上の理由があるかもしれません
ケイガンマットソン

4
同意する。HTTP 200応答で報告されるアプリケーション層エラーには何も問題はありません。200は、HTTP要求/応答自体が成功したことを示しますが、そのコンテンツまたはその時点で呼び出されるアプリケーション層のセマンティクスについては何も言いません。
モニカとの軽さレース

22

この質問は少し意見に基づいていますが、どちらにしてもです。

私の見方では、200は「ソフトエラー」に対応できます。APIの構築に関しては、これらと「ハードエラー」を区別しようとします。

「ソフトエラー」はステータスコード200で提供されますが、エラーの説明と成功ステータスが含まれますfalse。「ソフトエラー」は、結果が「予想どおり」である場合にのみ発生しますが、厳密な意味での成功ではありません。

「ソフトエラー」は実装者にとってより多くのヒントであることに注意することが重要です。そのため、人間が読み取れるエラーメッセージやエンドユーザーにフィードバックを提供するために使用できる何らかのコードなど、エラーに関する詳細情報を提供することも重要です。これらのエラーは、実装者(およびエンドユーザー)に、サーバー側で起こったことに関する詳細情報を提供します

たとえば、検索機能を備えたAPIを使用しているが、検索中に結果が得られなかったとします。これは誤りではありませんが、定義の厳密な意味ではなく、「成功」でもありません。

JSON形式の例:

{
    "meta" {
        "success": false,
        "message": "Search yielded no results",
        "code": "NORESULTS"
    }
    "data": []
}

一方、「ハードエラー」には、エラーに推奨されるステータスコードが表示されます。ユーザーがログインしていませんか?– 403/401。不正な入力ですか?–400。サーバーエラー?– 50X。等々。

繰り返しますが、それは少し意見に基づいています。一部の人々は、すべてのエラーを同等に扱い、すべてを「ハードエラー」にしたいと考えています。検索結果がありませんか?それは404です!コインの反対側には、検索結果はありませんか?–これは予想どおりであり、エラーはありません。

考慮すべきもう1つの重要な要素は、たとえばアーキテクチャです。JavaScript XHRリクエストとjQueryまたはAngularJSを使用してAPIとやり取りする場合。これらの「ハードエラー」は個別のコールバックで処理する必要がありますが、「ソフトエラー」は「成功」コールバックで処理できます。何も壊さず、結果はまだ「期待どおり」です。クライアント側のコードは、成功ステータスとコード(またはメッセージ)を確認できます。そして、それをエンドユーザーに印刷します。


2
実際、それをAPIレベルのエラーとして分類することは、奇妙な決定です。クライアントが彼の裁量で、ユーザーレベルで予期しないものとして分類する場合でも。
デデュプリケーター

1
考慮しなければならないことがたくさんあります。それはすべてAPIの実装に依存します。また、少し意見に基づいており、APIが「成功」および/または「エラー」と定義しているものまでです。"success": false-flagは、より多くのですヒント何かがアップだと実装します。通常、内部ステータスコードを使用する必要があります。どちらか"code": "NORESULTS"または数値コード-どのようなAPIの空想の生みの親。APIを実装する人はだれでも、サーバーで何が起こったかについての情報を差し引くことができます。
ダイマウス

15

APIには2つの側面があります。APIを実装する努力と、APIを正しく使用するためのすべてのクライアントの努力です。

クライアントの作成者として、Webサーバーに要求を送信すると、エラー(サーバーと適切に通信しなかった)が返されるか、ステータスコードが返されることがあります。エラーを処理する必要があります。私は良い応答を処理する必要があります。予想される文書化された「悪い」応答を処理する必要があります。戻ってくるものは何でも処理しなければなりません。

APIの設計では、クライアントが処理するのに最も簡単なものを検討する必要があります。クライアントが整形式のリクエストを送信し、リクエストで要求されていることを実行できる場合は、200の範囲で回答する必要があります(その範囲の200以外の数字が適切な場合があります)。

クライアントが「...のようなすべてのレコードをください」と尋ねて、ゼロがある場合、成功した200とゼロレコードの配列は完全に適切です。あなたが言及するケース:

「ログインに失敗しました」は通常401です。「ファイルを見つけられませんでした」は404です。「パラメータxがありません」は、500程度です(実際、サーバーがリクエストが悪いと判断した場合は400、500サーバーが私のリクエストによって完全に混乱し、何が起こっているのかわからない場合)。これらの場合に200を返すことは無意味です。クライアントの作成者として、ステータスコードを見るだけではなく、返信も検討する必要があるということです。「ステータス200、すばらしい、ここにデータがあります」とは言えません。

特に「パラメーターがありません」-それは私が今まで処理するものではありません。それは私の要求が間違っていることを意味します。私のリクエストが間違っている場合、その間違ったリクエストを修正するためのフォールバックはありません。最初に正しいリクエストを送信します。今、私はそれを処理することを余儀なくされています。200を取得し、「パラメーターがありません」という応答があるかどうかを確認する必要があります。それはひどい。

最終的に、多くの異なる状況を処理するための12個または2個のステータスコードがあり、それらを使用する必要があります。


3
APIに接続するとき、個人的には有効なエンドポイントに接続するときに「ファイルが見つかりません」で200を取得します。これにより、HTTP処理がその上のAPIを処理するレイヤーにブリードする必要がなくなります。
whatsisname

4
「パラメータxの欠落」は、クライアントが何か間違ったことをしているため、400 BAD_REQUESTである必要があります。500 INTERNAL_SERVER_ERRORは、サーバーが間違ったことをしている場合のために予約する必要があります。500は、クライアントが再試行できることを意味します。400は、誰かがクライアントを修正する必要があることを意味します。
ロボット

1
RESTfulインターフェースを作成している場合、URLは特定のオブジェクトを識別するため、404が適切です。概念的には/customers/premium/johndoe.json、データベースにない顧客を/files/morefiles/customers.html指し、ファイルシステムにないページを指す場合も同じです。
ロボット

@whatsisnameあなたが言っていることは理にかなっています。なぜなら、エンドポイントが悪いのか、リソースが存在しないのかが不明だからです。また、エンドポイントが有効であるかどうかにかかわらず、そのアドレスにリソースが存在しない404ため、両方のケースでa が正しいと主張することもできます。
ピート

2
言及していないことの1つは、アプリケーションエラーをHTTPステータスコードに便乗させると、情報が失われる可能性があることです。アプリが404を返すだけで、APIが404を返したのか、サーバーがファイルを見つけられなかったのかはわかりません。これにより、デバッグに1ステップ追加できます。
-AmadeusDrZaius
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.