ejemplo - httpurlconnection java example
Errorstream en HttpUrlConnection (5)
Quiero hacer una solicitud POST a un Servlet HTTP que escribí yo mismo. Buen caso (código de respuesta HTTP 200) siempre funciona bien usando el método URL.openConnection (). Pero cuando recibo un código de respuesta de error deseado (por ejemplo, 400), entonces pensé que tenía que usar HttpUrlConnection.getErrorStream (). Pero el objeto ErrorStream es nulo, aunque estoy enviando datos desde el servlet en caso de error (quiero evaluar estos datos para generar mensajes de error). Así es como se ve mi código:
HttpURLConnection con = null;
try {
//Generating request String
String request = "request="+URLEncoder.encode(xmlGenerator.getStringFromDocument(xmlGenerator.generateConnectRequest(1234)),"UTF-8");
//Receiving HttpUrlConnection (DoOutput = true; RequestMethod is set to "POST")
con = openConnection();
if (con != null){
PrintWriter pw = new PrintWriter(con.getOutputStream());
pw.println(request);
pw.flush();
pw.close();
InputStream errorstream = con.getErrorStream();
BufferedReader br = null;
if (errorstream == null){
InputStream inputstream = con.getInputStream();
br = new BufferedReader(new InputStreamReader(inputstream));
}else{
br = new BufferedReader(new InputStreamReader(errorstream));
}
String response = "";
String nachricht;
while ((nachricht = br.readLine()) != null){
response += nachricht;
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Así que mi pregunta es, ¿por qué devuelve getErrorStream () nulo a pesar de que el código de estado es 400 (puedo verlo en la excepción IOException que se genera cuando se llama con.getInputStream ())
Gracias
Cavando un poco en el código JDK, finalmente encuentro la razón. HttpURLConnection # getErrorStream () devuelve nulo al recibir un 401 o 407, no porque la implementación noop en la clase abstracta, sino porque HttpURLConnection cierra / borra la conexión inmediatamente si ve un 401/407 cuando está en modo de transmisión (es decir, POST). Vea la fuente de la implementación concreta de HttpURLConnection: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/sun/net/www/protocol/http/HttpURLConnection.java#1079
Dicho esto, cuando se detecta una excepción IOException al llamar a getInputStream (), la conexión al servidor ya está cerrada y el socket de subrayado está desactivado, por lo que siempre obtendría un valor nulo al llamar a getErrorStream ().
Las otras opciones que muchos han sugerido es verificar el código de estado antes de llamar a getInputStream o getErrorStream. Esto tampoco será para 401 y 407 porque el errorStream interno solo se establece cuando llama a getInputStream, es decir, es básicamente una copia de inputStream cuando el código de estado es = 200. Pero, nuevamente, cuando llame a getInputStream, la conexión se cerrará .
Como se sugiere en la documentación de Android :
String responseString;
try {
responseString = readInputStream(con.getInputStream());
} catch (final IOException e) {
// This means that an error occurred, read the error from the ErrorStream
try {
responseString = readInputStream(con.getErrorStream());
} catch (IOException e1) {
throw new IllegalStateException("Unable to read error body.", e);
}
}
private String readInputStream(final InputStream inputStream) throws IOException {
final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
final StringBuilder responseString = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
responseString.append(line);
}
bufferedReader.close();
return responseString.toString();
}
De la documentación de java en getErrorStream ():
Devuelve la secuencia de error si la conexión falló, pero el servidor envió datos útiles, no obstante. El ejemplo típico es cuando un servidor HTTP responde con un 404, lo que provocará que se genere una excepción FileNotFoundException, pero el servidor envió una página de ayuda HTML con sugerencias sobre qué hacer. Este método no hará que se inicie una conexión. Si la conexión no estaba conectada, o si el servidor no tuvo un error al conectarse o si el servidor tuvo un error pero no se enviaron datos de error, este método devolverá el valor nulo. Este es el valor predeterminado.
Por lo tanto, si no llegó al servidor (por ejemplo, la URL incorrecta) o si el servidor no envió nada en la respuesta, getErrorStream () devolverá el valor nulo.
Ponga la declaración conn.setAllowUserInteraction(true);
antes de ejecutar la solicitud y la conexión no se cerrará, incluso recibiendo el estado 401.
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setAllowUserInteraction(true); // <<<--- ### HERE
//do something
conn.connect();
boolean isError = (conn.getResponseCode() >= 400);
InputSteam is = isError ? con.getErrorStream() : con.getInputStream();
InputStream inputStream = null;
try {
inputStream = connection.getInputStream();
} catch(IOException exception) {
inputStream = connection.getErrorStream();
}
Es como cuando establece el código de estado del encabezado de respuesta como algo más allá de 200, el objeto de conexión se restablece. generará la excepción SocketTimeoutException al obtener el flujo de entrada, pero cuando llega al final, le da el flujo de entrada de todos modos, lo que está esperando.