web-dev-qa-db-fra.com

Lire le corps de la réponse aux erreurs dans Java

En Java, ce code lève une exception lorsque le résultat HTTP est de 404:

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

Dans mon cas, je sais que le contenu est 404, mais j'aimerais quand même lire le corps de la réponse.

(Dans mon cas, le code de réponse est 403, mais le corps de la réponse explique la raison du rejet, et j'aimerais l'afficher à l'utilisateur.)

Comment puis-je accéder au corps de réponse?

80
Dan Fabulich

Voici le rapport de bug (fermer, ne sera pas corrigé, pas un bug).

Leur conseil est de coder comme ceci:

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

C'est le même problème que j'avais: HttpUrlConnection renvoie FileNotFoundException si vous essayez de lire la getInputStream() à partir de la connexion.
Vous devriez plutôt utiliser getErrorStream() lorsque le code d'état est supérieur à 400.

Plus que cela, soyez prudent car ce n'est pas seulement 200 pour être le code d'état de réussite, même 201, 204, etc. sont souvent utilisés comme états de réussite.

Voici un exemple de la façon dont je suis allé le gérer

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

De cette façon, vous pourrez obtenir la réponse nécessaire dans les cas de réussite et d'erreur.

J'espère que cela t'aides!

13
gpiazzese

Dans .Net, vous avez la propriété Response de WebException qui donne accès au flux SUR une exception. Donc je suppose que c'est un bon moyen pour Java, ...

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

Ou une implémentation que j'ai utilisée. (Pourrait avoir besoin de modifications pour l'encodage ou d'autres choses. Fonctionne dans l'environnement actuel.)

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();
}
11
Vozzie

Vérifiez d'abord le code de réponse, puis utilisez HttpURLConnection.getErrorStream()

2
Chris Dolan

Je sais que cela ne répond pas directement à la question, mais au lieu d'utiliser la bibliothèque de connexions HTTP fournie par Sun, vous voudrez peut-être jeter un œil à Commons HttpClient , qui (à mon avis) a un API beaucoup plus facile à utiliser.

2
matt b
InputStream is = null;
if (httpConn.getResponseCode() !=200) {
    is = httpConn.getErrorStream();
} else {
     /* error from server */
    is = httpConn.getInputStream();
}
0
user253908