Lesen Sie den Fehlerantworttext in Java

91

In Java löst dieser Code eine Ausnahme aus, wenn das HTTP-Ergebnis im Bereich 404 liegt:

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

In meinem Fall weiß ich zufällig, dass der Inhalt 404 ist, aber ich möchte trotzdem den Text der Antwort lesen.

(In meinem tatsächlichen Fall lautet der Antwortcode 403, aber der Hauptteil der Antwort erklärt den Grund für die Ablehnung, und ich möchte dies dem Benutzer anzeigen.)

Wie kann ich auf den Antworttext zugreifen?

Dan Fabulich
quelle
Sind Sie sicher, dass der Server einen Text sendet?
Hank Gay
2
@jdigital: Die von HttpURLConnection.getInputStream () ausgelöste Ausnahme ist java.io.FileNotFoundException. (Hauptsächlich erwähnt dies für eine bessere Googlabilität.)
Jonik

Antworten:

168

Hier ist der Fehlerbericht (schließen, nicht beheben, kein Fehler).

Ihr Rat dort ist, wie folgt zu codieren:

HttpURLConnection httpConn = (HttpURLConnection)_urlConnection;
InputStream _is;
if (httpConn.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST) {
    _is = httpConn.getInputStream();
} else {
     /* error from server */
    _is = httpConn.getErrorStream();
}
TofuBeer
quelle
5
Möchten Sie den Fehlerstrom nicht erhalten, wenn der Antwortcode> = 400 ist, und nicht umgekehrt?
Stephen Swensen
3
Im Fehlerfall löst getInputStream () eine E / A-Ausnahme aus. Sie sollten die Ausnahme abfangen und mit getErrorStream () aus dem Fehlerstrom lesen. Dies scheint ein besserer Ansatz zu sein als die Überprüfung des httpresponse-Codes.
Sudarshan Bhat
3
Das Problem ist, dass wenn Sie den Code HttpUrlConnection.getErrorStream () lesen, Sie feststellen, dass er IMMER null zurückgibt. (Java 6) :-(
Gangnus
6
Werden andere Erfolgscodes wie "201 CREATED" hier nicht scheitern?
Rich
4
Der Fehlerbericht schlägt vor, zu überprüfen httpConn.getResponseCode() >= 400(und ihre Problemumgehung hat einen Fehler, der die zu verwendenden Eingabestreams umdreht)
Dag
14

Es ist das gleiche Problem, das ich hatte: HttpUrlConnectionGibt zurück, FileNotFoundExceptionwenn Sie versuchen, das getInputStream()von der Verbindung zu lesen .
Sie sollten stattdessen verwenden, getErrorStream()wenn der Statuscode höher als 400 ist.

Seien Sie darüber hinaus vorsichtig, da nicht nur 200 der Erfolgsstatuscode sind, sondern auch 201, 204 usw. häufig als Erfolgsstatus verwendet werden.

Hier ist ein Beispiel, wie ich es geschafft habe

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

Auf diese Weise erhalten Sie sowohl in Erfolgs- als auch in Fehlerfällen die erforderliche Antwort.

Hoffe das hilft!

gpiazzese
quelle
13

In .Net haben Sie die Response-Eigenschaft der WebException, die den Zugriff auf den Stream bei einer Ausnahme ermöglicht. Ich denke, das ist ein guter Weg für Java, ...

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

Oder eine Implementierung, die ich verwendet habe. (Möglicherweise sind Änderungen für die Codierung oder andere Dinge erforderlich. Funktioniert in der aktuellen Umgebung.)

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
quelle
Dies sollte die akzeptierte Antwort sein ... Ich frage mich, warum die Leute immer noch magische Zahlen überprüfen, anstatt Ausnahmen zu behandeln ...
SparK
Ich frage mich, warum dies nicht bei akzeptierter Antwort ist. Hat mir viel geholfen. Vielen Dank!
Nikhil Jain
2

Ich weiß, dass dies die Frage nicht direkt beantwortet, aber anstatt die von Sun bereitgestellte HTTP-Verbindungsbibliothek zu verwenden, sollten Sie sich Commons HttpClient ansehen , das (meiner Meinung nach) eine weitaus einfachere API bietet.

matt b
quelle
4
Ich bin anderer Ansicht. Die API von Sun ist viel einfacher, solange Sie die wirklich einfachen Dinge tun. Mit einfachen Dingen meine ich nur ein GET ohne zu viel Fehlerbehandlung, was für eine große Anzahl von Fällen ausreicht. Natürlich ist HttpClient in der Funktionalität weit überlegen.
Michael Piefel
Ab 2014 ist OkHttp möglicherweise das beste (das beim Öffnen einer URL tatsächlich HttpURLConnection-Instanzen zurückgibt). Insbesondere unter Android kann es Ihnen helfen, einige unangenehme Probleme sowohl mit einfachem HttpURLConnection als auch mit Apache HttpClient zu vermeiden.
Jonik
2

Überprüfen Sie zuerst den Antwortcode und verwenden Sie dann HttpURLConnection.getErrorStream()

Chris Dolan
quelle
1
InputStream is = null;
if (httpConn.getResponseCode() !=200) {
    is = httpConn.getErrorStream();
} else {
     /* error from server */
    is = httpConn.getInputStream();
}
etw
quelle
4
Werden andere Erfolgscodes wie "201 CREATED" hier nicht scheitern?
Rich
Ja @Rich, deshalb ist es besser zu tun:if (httpConn.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST) {
AO_
1

Mein laufender Code.

  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
quelle
0

So lesen Sie den 404-Antworttext in Java:

Verwenden Sie die Apache-Bibliothek - https://hc.apache.org/httpcomponents-client-4.5.x/httpclient/apidocs/

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

Das unten angegebene Snippet verwendet 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
quelle