Jak uzyskać treść odpowiedzi za pomocą HttpURLConnection, gdy zwracany jest kod inny niż 2xx?

98

Mam problem z pobraniem odpowiedzi Json w przypadku, gdy serwer zwróci błąd. Szczegóły poniżej.

Jak wykonuję żądanie

Używam java.net.HttpURLConnection. Konfiguruję właściwości żądania, a następnie:

conn = (HttpURLConnection) url.openConnection();

Następnie, gdy żądanie się powiedzie, otrzymuję odpowiedź Json:

br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
sb = new StringBuilder();
String output;
while ((output = br.readLine()) != null) {
  sb.append(output);
}
return sb.toString();

... a problem jest taki:

Nie mogę pobrać pliku Json otrzymanego, gdy serwer zwraca błąd, taki jak 50x lub 40x. Następujący wiersz zgłasza wyjątek IOException:

br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
// throws java.io.IOException: Server returned HTTP response code: 401 for URL: www.example.com

Serwer na pewno wysyła body, widzę to w zewnętrznym narzędziu Burp Suite:

HTTP/1.1 401 Unauthorized

{"type":"AuthApiException","message":"AuthApiException","errors":[{"field":"email","message":"Invalid username and/or password."}]}

Mogę otrzymać wiadomość z odpowiedzią (np. „Wewnętrzny błąd serwera”) i kod (np. „500”), korzystając z następujących metod:

conn.getResponseMessage();
conn.getResponseCode();

Ale nie mogę pobrać treści żądania ... może jest jakaś metoda, której nie zauważyłem w bibliotece?

kiedysktos
źródło

Odpowiedzi:

133

Jeśli kod odpowiedzi jest inny niż 200 lub 2xx, użyj getErrorStream()zamiastgetInputStream().

Markiz Lorne
źródło
3
w moim przypadku, mając kod odpowiedzi 403, getErrorStream () zwraca wartość null
Sip
72

Aby wszystko było jasne, oto mój działający kod:

if (100 <= conn.getResponseCode() && conn.getResponseCode() <= 399) {
    br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
} else {
    br = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
}
kiedysktos
źródło
3
HttpURLConnection.getErrorStream()( sun.net.www.protocol.httpimplementacja) zwraca, nullchyba że responseCode >= 400, więc Twój czek na 299 jest prawdopodobnie nieprawidłowy.
vladr
6
Jeśli używasz języka Java 8, możesz uzyskać odpowiedź w postaci ciągu. String responseBody = br.lines().collect(Collectors.joining());
Lanil Marasinghe
1
Prawidłowy zakres to 200 ... 399, ponieważ 3xx to stan „przekierowania”, a nie błąd.
luca.vercelli
1
@ luca.vercelli Myślę, że powinno być 100..399, ponieważ 100..199 to odpowiedzi „informacyjne” zdefiniowane w en.wikipedia.org/wiki/…
WindRider
4

Jest to łatwy sposób na uzyskanie pomyślnej odpowiedzi z serwera, na przykład wywołanie echa PHP, w przeciwnym razie komunikat o błędzie.

BufferedReader br = null;
if (conn.getResponseCode() == 200) {
    br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    String strCurrentLine;
        while ((strCurrentLine = br.readLine()) != null) {
               System.out.println(strCurrentLine);
        }
} else {
    br = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
    String strCurrentLine;
        while ((strCurrentLine = br.readLine()) != null) {
               System.out.println(strCurrentLine);
        }
}
Sharhabeel Hamdan
źródło
Świetne rozwiązanie! Wielkie dzięki.
Adrian Smith