Как получить тело ответа с помощью HttpURLConnection, когда возвращается код, отличный от 2xx?

98

У меня проблема с получением ответа Json в случае, если сервер возвращает ошибку. См. Подробности ниже.

Как я выполняю запрос

Пользуюсь java.net.HttpURLConnection. Я настраиваю свойства запроса, затем делаю:

conn = (HttpURLConnection) url.openConnection();

После этого при успешном запросе я получаю ответ Json:

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

... и проблема в следующем:

Я не могу получить Json, полученный, когда сервер возвращает ошибку, например 50x или 40x. Следующая строка выдает исключение IOException:

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

Сервер точно отправляет тело, я его вижу во внешнем инструменте Burp Suite:

HTTP/1.1 401 Unauthorized

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

Я могу получить ответное сообщение (например, «Внутренняя ошибка сервера») и код (например, «500»), используя следующие методы:

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

Но я не могу получить тело запроса ... может быть, есть какой-то метод, который я не заметил в библиотеке?

Кедисктос
источник

Ответы:

134

Если код ответа не 200 или 2xx, используйте getErrorStream()вместоgetInputStream().

Маркиз Лорн
источник
3
в моем случае, имея код ответа 403, getErrorStream () возвращает null
Sip
73

Чтобы прояснить ситуацию, вот мой рабочий код:

if (100 <= conn.getResponseCode() && conn.getResponseCode() <= 399) {
    br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
} else {
    br = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
}
Кедисктос
источник
3
HttpURLConnection.getErrorStream()( sun.net.www.protocol.httpреализация) возвращает, nullесли responseCode >= 400, поэтому ваша проверка на 299, вероятно, неверна.
vladr
6
Если вы используете Java 8, вы можете получить ответ в виде строки. String responseBody = br.lines().collect(Collectors.joining());
Ланил Марасингхе
1
Правильный диапазон - 200 ... 399, поскольку 3xx - это статус «перенаправления», а не ошибка.
luca.vercelli,
1
@ luca.vercelli Я думаю, что это должно быть 100..399, потому что 100..199 предназначены для "информационных" ответов, как определено в en.wikipedia.org/wiki/…
WindRider
4

Это простой способ получить успешный ответ от сервера, например PHP echo, иначе сообщение об ошибке.

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);
        }
}
Шархабил Хамдан
источник