Baca isi respons kesalahan di Java

93

Di Java, kode ini melontarkan pengecualian jika hasil HTTP adalah kisaran 404:

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

Dalam kasus saya, saya kebetulan tahu bahwa isinya adalah 404, tetapi saya tetap ingin membaca isi tanggapannya.

(Dalam kasus saya yang sebenarnya, kode responsnya adalah 403, tetapi isi respons menjelaskan alasan penolakan, dan saya ingin menampilkannya kepada pengguna.)

Bagaimana saya bisa mengakses isi respon?

Dan Fabulich
sumber
Apakah Anda yakin server mengirimkan badan?
Hank Gay
2
@jdigital: pengecualian yang ditampilkan oleh HttpURLConnection.getInputStream () adalah java.io.FileNotFoundException. (Terutama menyebutkan ini untuk googlabilitas yang lebih baik.)
Jonik

Jawaban:

172

Berikut adalah laporan bugnya (tutup, tidak akan diperbaiki, bukan bug).

Saran mereka ada kode seperti ini:

HttpURLConnection httpConn = (HttpURLConnection)_urlConnection;
InputStream _is;
if (httpConn.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST) {
    _is = httpConn.getInputStream();
} else {
     /* error from server */
    _is = httpConn.getErrorStream();
}
TofuBeer
sumber
5
Tidakkah Anda ingin mendapatkan aliran kesalahan saat kode responsnya> = 400, daripada sebaliknya?
Stephen Swensen
3
Jika terjadi kesalahan, getInputStream () akan menampilkan Pengecualian IO. Anda harus menangkap pengecualian dan membaca dari aliran kesalahan menggunakan getErrorStream (). Ini tampaknya menjadi pendekatan yang lebih baik daripada memeriksa kode httpresponse.
Sudarshan Bhat
3
Masalahnya adalah jika Anda membaca kode HttpUrlConnection.getErrorStream (), Anda akan melihat bahwa kode SELALU mengembalikan null. (Jawa 6) :-(
Gangnus
6
Tidakkah kode sukses lain seperti "201 CREATED" gagal di sini?
Kaya
4
Laporan bug menyarankan untuk memeriksa httpConn.getResponseCode() >= 400(dan penyelesaiannya memiliki kesalahan, membalik inputstream untuk digunakan)
Dag
14

Ini masalah yang sama dengan yang saya alami: HttpUrlConnectionkembali FileNotFoundExceptionjika Anda mencoba membaca getInputStream()dari koneksi.
Sebaiknya gunakan getErrorStream()jika kode status lebih tinggi dari 400.

Lebih dari itu, harap berhati-hati karena tidak hanya 200 yang menjadi kode status sukses, bahkan 201, 204, dsb. Sering digunakan sebagai status sukses.

Berikut adalah contoh bagaimana saya mengelolanya

... 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....

Dengan cara ini, Anda bisa mendapatkan respons yang dibutuhkan baik dalam kasus sukses maupun kesalahan.

Semoga ini membantu!

gpiazzese.dll
sumber
13

Di .Net Anda memiliki properti Respon dari WebException yang memberikan akses ke aliran ON pengecualian. Jadi saya rasa ini adalah cara yang baik untuk Java, ...

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

Atau implementasi yang saya gunakan. (Mungkin perlu perubahan untuk encoding atau hal lain. Berfungsi di lingkungan saat ini.)

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();
}
Vozzie
sumber
Ini harus menjadi jawaban yang diterima ... Saya bertanya-tanya mengapa orang masih memverifikasi nomor ajaib daripada menangani pengecualian ...
SparK
Saya bertanya-tanya mengapa ini bukan jawaban yang diterima. Banyak membantu saya. Terima kasih!
Nikhil Jain
2

Saya tahu bahwa ini tidak menjawab pertanyaan secara langsung, tetapi alih-alih menggunakan pustaka koneksi HTTP yang disediakan oleh Sun, Anda mungkin ingin melihat Commons HttpClient , yang (menurut saya) memiliki API yang jauh lebih mudah untuk digunakan.

matt b
sumber
4
Saya mohon untuk berbeda. API dari Sun jauh lebih mudah, selama Anda melakukan hal-hal yang sangat sederhana. Yang saya maksud dengan hal-hal sederhana hanyalah GET tanpa terlalu banyak penanganan kesalahan, yang cukup untuk sejumlah besar kasus. Tentu saja HttpClient jauh lebih unggul dalam fungsionalitas.
Michael Piefel
Pada 2014, yang terbaik mungkin OkHttp (yang benar-benar mengembalikan contoh HttpURLConnection saat membuka URL). Terutama di Android, ini dapat membantu Anda menghindari beberapa masalah buruk dari HttpURLConnection biasa & Apache HttpClient.
Jonik
2

Pertama periksa kode respon dan kemudian gunakan HttpURLConnection.getErrorStream()

Chris Dolan
sumber
1
InputStream is = null;
if (httpConn.getResponseCode() !=200) {
    is = httpConn.getErrorStream();
} else {
     /* error from server */
    is = httpConn.getInputStream();
}
sth
sumber
4
Tidakkah kode sukses lain seperti "201 CREATED" gagal di sini?
Kaya
Ya @ Kaya, itu sebabnya lebih baik dilakukan:if (httpConn.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST) {
AO_
1

Kode lari saya.

  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);
Durgesh Kumar
sumber
0

Cara membaca isi respons 404 di java:

Gunakan pustaka Apache - https://hc.apache.org/httpcomponents-client-4.5.x/httpclient/apidocs/

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

Cuplikan yang diberikan di bawah ini menggunakan 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());
Esakkiappan .E
sumber