2009-03-05 13 views
63

En Java, este código produce una excepción cuando el resultado es HTTP 404 rango:Leer cuerpo de la respuesta de error en Java

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

En mi caso, me he enterado de que el contenido es 404, pero me todavía me gusta leer el cuerpo de la respuesta de todos modos.

(En mi caso real del código de respuesta es 403, pero el cuerpo de la respuesta explica el motivo del rechazo, y me gusta mostrar que para el usuario.)

¿Cómo puedo acceder a la respuesta ¿cuerpo?

+0

¿Estás seguro de que el servidor está enviando un cuerpo? –

+0

¿Cuál es la excepción? – jdigital

+2

@jdigital: la excepción lanzada por HttpURLConnection.getInputStream() es java.io.FileNotFoundException. (Principalmente mencionar esto para una mejor googlability.) – Jonik

Respuesta

127

Here is the bug report (cerca, no van a resolver, no es un error).

Sus consejos que hay que codificar así:

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

Parece de hecho "como se esperaba", dado el diseño de la API, me parece razonable –

+4

¿No le gustaría obtener la secuencia de error cuando el código de respuesta es> = 400, en lugar de al revés? –

+0

@Stephen Sí, supongo que sí, pero acabo de tomar el código en el enlace ... – TofuBeer

2

Sé que esto no responde la pregunta directamente, pero en lugar de utilizar la biblioteca de conexiones HTTP proporcionada por Sun, es posible que desee echar un vistazo a Commons HttpClient, que (en mi opinión) tiene una API mucho más fácil de trabajar con.

+4

Yo me permito diferir. La API de Sun es mucho más fácil, siempre que hagas las cosas realmente simples. Simplemente me refiero a un GET sin demasiado manejo de errores, que es suficiente para una gran cantidad de casos. Por supuesto, HttpClient es muy superior en funcionalidad. –

+0

A partir de 2014, lo mejor podría ser [OkHttp] (http://square.github.io/okhttp/) (que en realidad devuelve instancias de HttpURLConnection al abrir una URL). Especialmente en Android puede ayudarte a evitar algunos problemas desagradables tanto de HttpURLConnection como de Apache HttpClient. – Jonik

2

primer lugar, compruebe el código de respuesta y luego utilice HttpURLConnection.getErrorStream()

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

¿No fallarán aquí otros códigos de éxito como "201 CREATED"? – Rich

+0

Sí @Rich, es por eso que es mejor hacer: 'if (httpConn.getResponseCode()

10

Es el mismo problema que tenía: HttpUrlConnection vuelve FileNotFoundException si intenta leer el getInputStream() de la conexión.
su lugar, debe utilizar getErrorStream() cuando el código de estado es mayor que 400.

Más que esto, por favor tener cuidado ya que no es sólo de 200 a ser el código de estado de éxito, incluso 201, 204, etc., se utilizan a menudo como estados de éxito.

Aquí es un ejemplo de cómo fui a manejarlo

... 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 esta manera, usted será capaz de obtener la respuesta necesaria en ambos casos de éxito y error.

Espero que esto ayude!

6

En .Net tiene la propiedad de respuesta de WebException que da acceso a la transmisión ON en una excepción. Así que supongo que esta es una buena forma para Java, ...

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

O una implementación que he utilizado. (Puede necesitar cambios para la codificación u otras cosas. Funciona en el entorno actual.)

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

Esta debería ser la respuesta aceptada ... Me pregunto por qué las personas todavía verifican números mágicos en lugar de manejar excepciones ... – SparK

Cuestiones relacionadas