2009-03-05 6 views
63

En Java, ce code renvoie une exception lorsque le résultat HTTP est 404 plage:Lire le corps de réponse d'erreur Java

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 je aime toujours lire le corps de la réponse de toute façon.

(Dans mon cas réel le code de réponse est 403, mais le corps de la réponse explique la raison du rejet, et je voudrais afficher que pour l'utilisateur.)

Comment puis-je accéder à la réponse corps?

+0

Etes-vous sûr que le serveur envoie un corps? –

+0

Quelle est l'exception? – jdigital

+2

@jdigital: l'exception renvoyée par HttpURLConnection.getInputStream() est java.io.FileNotFoundException. (Principalement mentionnant cela pour une meilleure googlability.) – Jonik

Répondre

127

Here is the bug report (près, ne fixerai pas, pas un bug).

Leurs conseils, il est à 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(); 
} 
+0

Semble en effet "comme prévu" étant donné la conception de l'API, semble raisonnable pour moi –

+4

Voulez-vous pas obtenir le flux d'erreur lorsque le code de réponse est> = 400, plutôt que l'inverse? –

+0

@Stephen oui, je suppose, mais je viens de saisir le code sur le lien ... – TofuBeer

2

Je sais que cela ne répond pas directement à la question, mais au lieu d'utiliser la bibliothèque de connexion HTTP fournie par Sun, vous pouvez jeter un oeil à Commons HttpClient, qui (à mon avis) a une API beaucoup plus facile à travailler avec.

+4

Je ne suis pas d'accord. L'API de Sun est beaucoup plus facile, tant que vous faites les choses vraiment simples. Par simple truc, je veux dire juste GET sans trop de gestion des erreurs, ce qui est suffisant pour un grand nombre de cas. Bien sûr, HttpClient est de loin supérieur en fonctionnalités. –

+0

À partir de 2014, le mieux pourrait être [OkHttp] (http://square.github.io/okhttp/) (qui renvoie réellement les instances HttpURLConnection lors de l'ouverture d'une URL). Surtout sur Android, il peut vous aider à éviter certains problèmes de HttpURLConnection et Apache HttpClient. – Jonik

2

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

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

Les autres codes de succès comme "201 CREATED" ne peuvent-ils pas échouer? – Rich

+0

Yes @Rich, C'est pourquoi il vaut mieux faire: 'if (httpConn.getResponseCode()

10

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

Plus que cela, s'il vous plaît faites attention car il est non seulement 200 à être le code d'état de réussite, même 201, 204, etc. sont souvent utilisés comme statuts de succès.

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 serez en mesure d'obtenir la réponse nécessaire dans les deux cas de réussite et d'erreur.

Espérons que cela aide!

6

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. (Peut nécessiter des 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(); 
} 
+0

Cela devrait être la réponse acceptée ... Je me demande pourquoi les gens vérifient encore les nombres magiques au lieu de gérer les exceptions ... – SparK

Questions connexes