2009-03-05 9 views
63

In Java, questo codice genera un'eccezione quando il risultato è HTTP 404 gamma:Leggi corpo risposta di errore in Java

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

Nel mio caso, mi capita di sapere che il contenuto è 404, ma mi piacerebbe mi piace ancora leggere il corpo della risposta comunque.

(Nel mio caso reale il codice di risposta è 403, ma il corpo della risposta spiega il motivo del rifiuto, e vorrei per visualizzare che per l'utente.)

Come posso accedere alla risposta corpo?

+0

Sei sicuro che il server sta inviando un corpo? –

+0

Qual è l'eccezione? – jdigital

+2

@jdigital: l'eccezione generata da HttpURLConnection.getInputStream() è java.io.FileNotFoundException. (Principalmente menzionando questo per una migliore googlability.) – Jonik

risposta

127

Here is the bug report (vicino, non risolverà, non un bug).

Il loro consiglio che c'è da codice come questo:

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

Sembra davvero "come previsto" data la progettazione dell'API, mi sembra ragionevole –

+4

Non vorresti ottenere il flusso di errori quando il codice di risposta è> = 400, piuttosto che il contrario? –

+0

@Stephen sì, presumo di sì, ma ho appena afferrato il codice al collegamento ... – TofuBeer

2

So che questo non risponde direttamente alla domanda, ma invece di utilizzare la libreria di connessioni HTTP fornita da Sun, potresti dare un'occhiata a Commons HttpClient, che (a mio parere) ha un'API molto più semplice da lavorare con.

+4

Mi permetto di dissentire. L'API di Sun è molto più semplice, a patto che tu faccia cose davvero semplici. Per cose semplici intendo solo un GET senza troppa gestione degli errori, che è sufficiente per un gran numero di casi. Ovviamente HttpClient è di gran lunga superiore in termini di funzionalità. –

+0

A partire dal 2014, la migliore potrebbe essere [OkHttp] (http://square.github.io/okhttp/) (che in realtà restituisce istanze HttpURLConnection all'apertura di un URL). Soprattutto su Android può aiutarti a evitare alcuni problemi di HttpURLConnection e Apache HttpClient. – Jonik

2

Prima controlla il codice di risposta e quindi usare HttpURLConnection.getErrorStream()

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

Impossibile che altri codici di successo come "201 CREATED" falliscano? – Rich

+0

Sì @Rich, ecco perché è meglio fare: 'if (httpConn.getResponseCode()

10

E 'lo stesso problema che stavo avendo: HttpUrlConnection restituisce FileNotFoundException se si tenta di leggere il getInputStream() dalla connessione.
Si dovrebbe invece usare getErrorStream() quando il codice di stato è superiore a 400.

Più di questo, si prega di fare attenzione in quanto non è solo 200 per essere il codice di stato di successo, anche 201, 204, ecc sono spesso usati come stati di successo.

Ecco un esempio di come sono andato a gestirlo

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

In questo modo, sarete in grado di ottenere la risposta necessaria in entrambi i casi di successo e di errore.

Spero che questo aiuti!

6

In .Net si ha la proprietà Response di WebException che dà accesso allo stream su un'eccezione. Quindi immagino che questo sia un buon modo per Java, ...

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

O una implementazione che ho usato. (Potrebbe essere necessario apportare modifiche per la codifica o altre cose.)

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

Questa dovrebbe essere la risposta accettata ... Mi chiedo perché le persone continuano a verificare i numeri magici invece di gestire le eccezioni ... – SparK