Como obter o corpo da resposta usando HttpURLConnection, quando um código diferente de 2xx é retornado?

95

Tenho problemas em recuperar a resposta Json caso o servidor retorne um erro. Veja os detalhes abaixo.

Como faço a solicitação

Eu uso java.net.HttpURLConnection. Eu configuro as propriedades da solicitação, então:

conn = (HttpURLConnection) url.openConnection();

Depois disso, quando a solicitação é bem-sucedida, recebo a resposta Json:

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

... e o problema é:

Não consigo recuperar o Json recebido quando o servidor retorna algum erro como 50x ou 40x ,. A linha a seguir lança IOException:

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

O servidor envia corpo com certeza, vejo na ferramenta externa Burp Suite:

HTTP/1.1 401 Unauthorized

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

Posso obter a mensagem de resposta (ou seja, "Erro interno do servidor") e o código (ou seja, "500") usando os seguintes métodos:

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

Mas não consigo recuperar o corpo da solicitação ... talvez haja algum método que não observei na biblioteca?

kiedysktos
fonte

Respostas:

132

Se o código de resposta não for 200 ou 2xx, use em getErrorStream()vez degetInputStream().

Marquês de Lorne
fonte
2
no meu caso, tendo um código de resposta 403, getErrorStream () retorna nulo
Sip de
68

Para deixar as coisas bem claras, aqui está meu código de trabalho:

if (200 <= conn.getResponseCode() && conn.getResponseCode() <= 399) {
    br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
} else {
    br = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
}
kiedysktos
fonte
3
HttpURLConnection.getErrorStream()( sun.net.www.protocol.httpimplementação) retorna a nullmenos que responseCode >= 400, portanto, sua verificação para 299 provavelmente está incorreta.
vladr
5
Se você estiver usando Java 8, poderá obter a resposta como uma String. String responseBody = br.lines().collect(Collectors.joining());
Lanil Marasinghe
1
O intervalo correto é 200 ... 399, pois 3xx é um status de "redirecionamento", não um erro.
luca.vercelli
1

Esta é uma maneira fácil de obter uma resposta bem-sucedida do servidor, como o PHP echo, caso contrário, uma mensagem de erro.

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
fonte