web-dev-qa-db-ja.com

REST AP​​I 404:不適切なURI、またはリソースが見つかりませんか?

REST AP​​Iを構築していますが、問題が発生しました。

REST AP​​Iの設計で一般に認められている方法は、要求されたリソースが存在しない場合は404が返されることです。

しかし、私にとって、これは不必要なあいまいさを追加します。 HTTP 404は伝統的に悪いURIと関連付けられています。つまり、実際には「正しい場所にたどり着きましたが、その特定のレコードは存在しません。またはインターネット上にそのような場所はありません!I 'どれがどれなのか本当によくわかりません... "

次のURIを考えてください。

http://mywebsite/api/user/13

404が返ってきたら、ユーザー13が存在しないからでしょうか。それとも、私のURLになっているはずです。

http://mywebsite/restapi/user/13

過去には、レコードが存在しない場合、HTTP 200 OKレスポンスコードと共にNULLの結果を返しました。それは単純です、そして私の意見ではそれが必ずしも受け入れられた練習ではないとしても非常にきれいです。しかし、これを実行するためのより良い方法はありますか?

176
Brian Lacy

404は単なるHTTPレスポンスコードです。それに加えて、開発者が見ることになるより意味のあるエラーメッセージを含むレスポンスボディや他のヘッダを提供することができます。

80
Robert Levy

リソースが存在しない場合は404を使用してください。空のボディで200を返さないでください。

これはプログラミングにおけるundefinedと空の文字列(例えば"")のようなものです。非常によく似ていますが、間違いなく違いがあります。

404は、そのURIに何も存在しないことを意味します(プログラミングの未定義変数のように)。空のボディで200を返すことは、何かがそこに存在していること、そして何かが今ちょうど空であることを意味します(プログラミングの空の文字列のように)。

404は、それが「悪いURI」であるという意味ではありません。 URIエラーを意図した特別なHTTPコードがあります(例:414 Request-URI Too Long)。

46
nategood

ほとんどのものと同様に、「それは依存します」。しかし、私にとって、あなたの習慣は悪くないし、HTTPの仕様に反することはないそれ自体。しかし、いくつか明確にしましょう。

まず、URIは不透明であるべきです。たとえそれらが人々に対して不透明でなくても、それらは機械に対して不透明です。言い換えれば、http://mywebsite/api/user/13http://mywebsite/restapi/user/13の違いは、http://mywebsite/api/user/13http://mywebsite/api/user/14の違いと同じです。同じでないことは、同じ期間ではありません。そのため、404はhttp://mywebsite/api/user/14に完全に適していますが(そのようなユーザーがいない場合)、必ずしも唯一の適切な応答ではありません。

空の200のレスポンス、またはより明示的に204(No Content)のレスポンスを返すこともできます。これは他に何かをクライアントに伝えるでしょう。 http://mywebsite/api/user/14によって識別されるリソースにはコンテンツがないか、本質的には何もないことを意味します。それはisそのようなリソースがあるという意味です。ただし、ID 14のデータストアにユーザーが保持されていると主張しているわけではありません。これは、クライアントが要求を出すことではなく、あなたの私的な問題です。したがって、リソースをそのようにモデル化することが理にかなっている場合は、先に進みます。

正当なURIを推測しやすくする情報をクライアントに提供することには、セキュリティ上の影響があります。 404ではなく200をミスして返すと、クライアントに少なくともhttp://mywebsite/api/user部分が正しいという手がかりを与える可能性があります。悪意のあるクライアントは異なる整数を試し続けることができます。しかし、私にとっては、悪意のあるクライアントがとにかくhttp://mywebsite/api/userの部分を推測できる可能性があります。もっと良い解決策はUUIDを使うことでしょう。すなわちhttp://mywebsite/api/user/3dd5b770-79ea-11e1-b0c4-0800200c9a66http://mywebsite/api/user/14より優れています。そうすることで、あなたは大したことをあきらめずに200を返すという自分のテクニックを使うことができます。

17
jhericks

404 Not Found技術的に言うと、uriはリソースにマップしませんmap。あなたの例では、私は404を返すhttp://mywebsite/api/user/13へのリクエストを解釈して、このURLがneverリソースにマップされたことを意味します。クライアントにとっては、これで会話は終了です。

あいまいさの問題に対処するために、他の応答コードを提供することによってAPIを強化できます。たとえば、クライアントにURL http://mywebsite/api/user/13へのGETリクエストの発行を許可したい場合、クライアントが正規のURL http://mywebsite/restapi/user/13を使用するように通知します。その場合は、1 Moved Permanentlyを返すことで永続的なリダイレクトを発行し、応答のLocationヘッダーに正規のURLを指定することを検討してください。これはクライアントに将来のリクエストには正規のURLを使うように伝えます。

10

したがって、本質的には、答えは要求がどのように形成されるかに依存する可能性があるように思えます。

要求されたリソースがhttp://mywebsite/restapi/user/13への要求に従ってURIの一部を形成し、ユーザ13が存在しない場合、URIは存在しないユーザ/エンティティ/文書などを表すので404はおそらく適切で直感的です。 GUID http://mywebsite/api/user/3dd5b770-79ea-11e1-b0c4-0800200c9a66および上記のapi/restapi引数を使用した、より安全な手法についても同じことが言えます。

ただし、要求されたリソースIDが要求ヘッダーに含まれている場合(実際の例を含む)、または実際にはパラメーターとしてURIに含まれている場合(例えばhttp://mywebsite/restapi/user/?UID=13)、URIは依然として正しいでしょう(USERの概念はhttp://mywebsite/restapi/user/で終了します) ;したがって、13として知られる特定のユーザーは存在しないがURIは存在するため、応答は200(適切な詳細メッセージを含む)であると合理的に予想されます。このように、私たちはURIは良いと言っていますが、データの要求には内容がありません。

個人的には200はまだ正しいとは言えません(私が以前にそれを主張したことがありますが)。 200応答コード(詳細応答なし)は、たとえば、誤ったIDが送信されたときに問題が調査されない原因になる可能性があります。

もっと良い方法は204 - No Content応答を送ることでしょう。これはw3cの説明に準拠しています*サーバは要求を満たしていますが、エンティティボディを返す必要はないため、更新されたメタ情報を返したい場合があります。* 1混乱は私の考えではウィキペディアのエントリが原因です 204コンテンツなし - サーバーは要求を正常に処理しましたが、コンテンツを返していません。 通常、成功した削除要求に対する応答として使用されます最後の文は非常に議論の余地があります。その文がない状況を考えれば解決策は簡単です - 実体が存在しない場合は204を送信してください。 404ではなく204を返すための引数もあります。要求は処理され、コンテンツは返されませんでした。ただし、204年代はレスポンスボディのコンテンツを許可していません。

出典

http://en.wikipedia.org/wiki/List_of_HTTP_status_codes 1. http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

8
john

この古くて素晴らしい記事... http://www.infoq.com/articles/webber-rest-workflow これについての...

404 Not Found - このサービスは私たちの要求が失敗した本当の理由を私たちに与えるにはあまりにも怠惰(または安全)ですが、どんな理由であれ、私たちはそれに対処する必要があります。

7

それは非常に古い投稿ですが、私は同様の問題に直面しました、そして私はあなたと私の経験を共有したいと思います。

私は残りのAPIでマイクロサービスアーキテクチャを構築しています。私はいくつかの残りのGETサービスを持っています、それらはリクエストパラメータに基づいてバックエンドシステムからデータを収集します。

残りのAPI設計ドキュメントをたどり、クエリ条件に一致するデータがない場合(たとえば、ゼロレコードが選択されたなど)、完璧なJSONエラーメッセージを使用してHTTP 404をクライアントに返送しました。

クライアントに返送するデータがない場合、内部エラーコードなどを含む完璧なJSONメッセージを作成して、 "Not Found"の理由をクライアントに通知し、HTTP 404を使用してクライアントに返送しました。正常に動作します。

その後、HTTP通信関連のコードを隠すための簡単なヘルパーであるrest APIクライアントクラスを作成しました。私は自分のコードからrest APIを呼び出すときに常にこのヘルパーを使用しました。

しかし、HTTP 404には2つの異なる機能があるという理由だけで、わかりにくいコードを書く必要がありました。

  • 指定されたURLでrest APIが利用できない場合は実際のHTTP 404、rest APIアプリケーションが実行されているアプリケーションサーバーまたはWebサーバーによってスローされます。
  • クエリのwhere条件に基づいてデータベースにデータがない場合も、クライアントはHTTP 404を返します。

Important:私のrest APIエラーハンドラはバックエンドサービスに現れるすべての例外をキャッチします。つまり、エラーが発生した場合、私のrest APIは常にメッセージの詳細を含む完璧なJSONメッセージを返します。

これは、2つの異なるHTTP 404応答を処理する私のクライアントヘルパーメソッドの最初のバージョンです。

public static String getSomething(final String uuid) {
    String serviceUrl = getServiceUrl();
    String path = "user/" + , uuid);
    String requestUrl = serviceUrl + path;
    String httpMethod = "GET";

    Response response = client
            .target(serviceUrl)
            .path(path)
            .request(ExtendedMediaType.APPLICATION_UTF8)
            .get();

    if (response.getStatus() == Response.Status.OK.getStatusCode()) {
        // HTTP 200
        return response.readEntity(String.class);
    } else {
        // confusing code comes here just because
        // I need to decide the type of HTTP 404...

        // trying to parse response body
        try {
            String responseBody = response.readEntity(String.class);
            ObjectMapper mapper = new ObjectMapper();
            ErrorInfo errorInfo = mapper.readValue(responseBody, ErrorInfo.class);

            // re-throw the original exception
            throw new MyException(errorInfo);

        } catch (IOException e) {
            // this is a real HTTP 404
            throw new ServiceUnavailableError(response, requestUrl, httpMethod);
        }

    // this exception will never be thrown
    throw new Exception("UNEXPECTED ERRORS, BETTER IF YOU DO NOT SEE IT IN THE LOG");
}

BUT、私のJavaまたはJavaScriptクライアントはどういうわけか2つの種類のHTTP 404を受け取ることができるので、HTTP 404の場合は応答の本文をチェックする必要があります。クライアントに返送するデータがないところで応答が返ってきたことを確認してください。

応答を解析できない場合は、Webサーバーから(残りのAPIアプリケーションからではなく)実際のHTTP 404を取得したことになります。

それはとても混乱していて、クライアントアプリケーションは常にHTTP 404の本当の理由をチェックするために余分な解析をする必要があります。

正直なところ、私はこの解決策が好きではありません。それは紛らわしいです、いつも余分なでたらめなコードをクライアントに加える必要があります。

そのため、この2つの異なるシナリオでHTTP 404を使用する代わりに、次のことを実行することにしました。

  • 私はもう私の残りのアプリケーションでレスポンスHTTPコードとしてHTTP 404を使用していません。
  • HTTP 404ではなくHTTP 204(No Content)を使用します。

その場合、クライアントコードはより洗練されたものになります。

public static String getString(final String processId, final String key) {
    String serviceUrl = getServiceUrl();
    String path = String.format("key/%s", key);
    String requestUrl = serviceUrl + path;
    String httpMethod = "GET";

    log(requestUrl);

    Response response = client
            .target(serviceUrl)
            .path(path)
            .request(ExtendedMediaType.APPLICATION_JSON_UTF8)
            .header(CustomHttpHeader.PROCESS_ID, processId)
            .get();

    if (response.getStatus() == Response.Status.OK.getStatusCode()) {
        return response.readEntity(String.class);
    } else {
        String body = response.readEntity(String.class);
        ObjectMapper mapper = new ObjectMapper();
        ErrorInfo errorInfo = mapper.readValue(body, ErrorInfo.class);
        throw new MyException(errorInfo);
    }

    throw new AnyServerError(response, requestUrl, httpMethod);
}

私はこれがその問題をよりよく処理すると思います。

よりよい解決策がある場合は、私たちと共有してください。

5
zappee

Uniform Resource Identifierは、リソースへの一意のポインタです。不十分な形式のURIはリソースを指していないため、GETを実行してもリソースは返されません。 404は、サーバーがRequest-URIに一致するものを見つけられなかったことを意味します。間違ったURIや間違ったURIを入力した場合、それがあなたの問題であり、HTMLページであろうとIMGであろうとリソースにアクセスできませんでした。

1
suing

このシナリオでは、HTTP 404は、REST AP​​Iからの応答の応答コードです(400、401、404、422など)

例外処理を使用して、完全な例外メッセージを確認してください。

try{
  // call the rest api
} catch(RestClientException e) {
     //process exception
     if(e instanceof HttpStatusCodeException){
        String responseText=((HttpStatusCodeException)e).getResponseBodyAsString();
         //now you have the response, construct json from it, and extract the errors
         System.out.println("Exception :" +responseText);
     }

}

この例外ブロックは、REST AP​​Iによってスローされた適切なメッセージを示します。

0