Javaでエラーレスポンスの本文を読み取る


93

Javaでは、このコードは、HTTPの結果が404の範囲である場合に例外をスローします。

URL url = new URL("http://stackoverflow.com/asdf404notfound");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.getInputStream(); // throws!

私の場合、たまたまコンテンツが404であることは知っていますが、とにかく応答の本文を読みたいと思います。

(私の実際の場合、応答コードは403ですが、応答の本文には拒否の理由が説明されているので、それをユーザーに表示します。)

応答本文にアクセスするにはどうすればよいですか?


サーバーが本文を送信してもよろしいですか?
ハンクゲイ

2
@jdigital:HttpURLConnection.getInputStream()によってスローされる例外はjava.io.FileNotFoundExceptionです。(主にこれはグーグル性を向上させるために言及しています。)
Jonik

回答:


172

これはバグレポートです(閉じる、修正しない、バグではない)。

彼らのアドバイスは次のようにコーディングすることです:

HttpURLConnection httpConn = (HttpURLConnection)_urlConnection;
InputStream _is;
if (httpConn.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST) {
    _is = httpConn.getInputStream();
} else {
     /* error from server */
    _is = httpConn.getErrorStream();
}

5
応答コードが400以上の場合、逆ではなくエラーストリームを取得しませんか?
Stephen Swensen、

3
エラーが発生した場合、getInputStream()はIO例外をスローします。例外をキャッチし、getErrorStream()を使用してエラーストリームから読み取る必要があります。これは、httpresponseコードをチェックするよりも優れたアプローチのようです。
Sudarshan Bhat 2012

3
問題は、HttpUrlConnection.getErrorStream()コードを読み取ると、常にnullが返されることです。(Java 6):-(
Gangnus 14年

6
「201 CREATED」のような他の成功コードはここで失敗しませんか?
リッチ

4
バグレポートは、チェックオンを提案しますhttpConn.getResponseCode() >= 400(そしてその回避策にはエラーがあり、使用する入力ストリームを反転します)
Dag

14

それは私が抱えていたのと同じ問題です: HttpUrlConnection返品FileNotFoundExceptiongetInputStream()です。接続からを読み取ろうとすると。ステータスコードが400より大きい場合は、
代わりに使用する必要がgetErrorStream()あります。

成功ステータスコードは200だけでなく、201、204などでも成功ステータスとして使用されることが多いので、これ以上注意してください。

これは私がそれを管理するために行った方法の例です

... connection code code code ...

// Get the response code 
int statusCode = connection.getResponseCode();

InputStream is = null;

if (statusCode >= 200 && statusCode < 400) {
   // Create an InputStream in order to extract the response object
   is = connection.getInputStream();
}
else {
   is = connection.getErrorStream();
}

... callback/response to your handler....

このようにして、成功した場合とエラーの場合の両方で必要な応答を取得できます。

お役に立てれば!


13

.Netには、例外でストリームへのアクセスを提供するWebExceptionのResponseプロパティがあります。これはJavaにとって良い方法だと思います...

private InputStream dispatch(HttpURLConnection http) throws Exception {
    try {
        return http.getInputStream();
    } catch(Exception ex) {
        return http.getErrorStream();
    }
}

または私が使用した実装。(エンコーディングなどの変更が必要になる場合があります。現在の環境で動作します。)

private String dispatch(HttpURLConnection http) throws Exception {
    try {
        return readStream(http.getInputStream());
    } catch(Exception ex) {
        readAndThrowError(http);
        return null; // <- never gets here, previous statement throws an error
    }
}

private void readAndThrowError(HttpURLConnection http) throws Exception {
    if (http.getContentLengthLong() > 0 && http.getContentType().contains("application/json")) {
        String json = this.readStream(http.getErrorStream());
        Object oson = this.mapper.readValue(json, Object.class);
        json = this.mapper.writer().withDefaultPrettyPrinter().writeValueAsString(oson);
        throw new IllegalStateException(http.getResponseCode() + " " + http.getResponseMessage() + "\n" + json);
    } else {
        throw new IllegalStateException(http.getResponseCode() + " " + http.getResponseMessage());
    }
}

private String readStream(InputStream stream) throws Exception {
    StringBuilder builder = new StringBuilder();
    try (BufferedReader in = new BufferedReader(new InputStreamReader(stream))) {
        String line;
        while ((line = in.readLine()) != null) {
            builder.append(line); // + "\r\n"(no need, json has no line breaks!)
        }
        in.close();
    }
    System.out.println("JSON: " + builder.toString());
    return builder.toString();
}

これは受け入れられる答えになるはずです...なぜ人々が例外を処理する代わりにマジックナンバーを検証するのか...
SparK

なぜこれは受け入れられた答えではないのでしょうか。私を大いに助けてくれました。ありがとう!
Nikhil Jain

2

私はこれが質問に直接答えることはないことを知っていますが、Sunが提供するHTTP接続ライブラリを使用する代わりに、(私の意見では)はるかに簡単に操作できるAPIを備えたCommons HttpClientを確認することをお勧めします。


4
失礼ですが同意できません。SunのAPIは、本当にシンプルなものを実行する限り、はるかに簡単です。単純なものとは、エラー処理をあまり行わずにGETを行うことを意味します。これは、多くの場合に十分です。もちろんHttpClientは機能的にはるかに優れています。
Michael Piefel、2011年

2014年現在、OkHttp(URLを開いたときに実際にHttpURLConnectionインスタンスを返す)が最適です。特にAndroidでは、プレーンなHttpURLConnectionとApache HttpClientの両方の厄介な問題を回避するのに役立ちます。
Jonik、2014年


1
InputStream is = null;
if (httpConn.getResponseCode() !=200) {
    is = httpConn.getErrorStream();
} else {
     /* error from server */
    is = httpConn.getInputStream();
}

4
「201 CREATED」のような他の成功コードはここで失敗しませんか?
リッチ

はい、@リッチです。そのため、次の方法をお勧めしますif (httpConn.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST) {
。– AO_

1

私の実行コード。

  HttpURLConnection httpConn = (HttpURLConnection) urlConn;    
 if (httpConn.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST) {
                        in = new InputStreamReader(urlConn.getInputStream());
                        BufferedReader bufferedReader = new BufferedReader(in);
                        if (bufferedReader != null) {
                            int cp;
                            while ((cp = bufferedReader.read()) != -1) {
                                sb.append((char) cp);
                            }
                            bufferedReader.close();
                        }
                            in.close();

                    } else {
                        /* error from server */
                        in = new InputStreamReader(httpConn.getErrorStream());
                    BufferedReader bufferedReader = new BufferedReader(in);
                    if (bufferedReader != null) {
                        int cp;
                        while ((cp = bufferedReader.read()) != -1) {
                            sb.append((char) cp);
                        }
                        bufferedReader.close();
                    }    
                    in.close();
                    }
                    System.out.println("sb="+sb);

0

Javaで404レスポンスボディを読み取る方法:

Apacheライブラリを使用-https ://hc.apache.org/httpcomponents-client-4.5.x/httpclient/apidocs/

またはJava 11- https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpClient.html

以下のスニペットはApacheを使用しています:

import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.util.EntityUtils;

CloseableHttpClient client = HttpClients.createDefault();
CloseableHttpResponse resp = client.execute(new HttpGet(domainName + "/blablablabla.html"));
String response = EntityUtils.toString(resp.getEntity());
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.