Ошибка в HttpUrlConnection
Я хочу сделать запрос POST на HTTP-сервлет, который я написал сам. Хороший случай (HTTP-код ответа 200) всегда отлично работает с использованием метода URL.openConnection(). Но когда я получаю желаемый код ответа на ошибку (например, 400), тогда я думал, что должен использовать HttpUrlConnection.getErrorStream(). Но объект ErrorStream имеет значение null, хотя я возвращаю данные из сервлета в случае ошибки (я хочу оценить эти данные для генерации сообщений об ошибках).
Вот как выглядит мой код:
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();
}
Итак, мой вопрос в том, почему возвращает getErrorStream() null, хотя статус-код равен 400 (я вижу его в IOException, которое вызывается при вызове con.getInputStream())
Спасибо
Ответы
Ответ 1
Из документации java на getErrorStream():
Возвращает поток ошибок, если соединение не удалось, но сервер отправил полезные данные. Типичным примером является то, что HTTP-сервер отвечает 404, что вызовет исключение FileNotFoundException в соединение, но сервер отправил справочную страницу HTML с предложениями относительно того, что делать. Этот метод не приведет к инициированию соединения. Если соединение не было подключено или если на сервере не было ошибки при подключении или если у сервера была ошибка, но никаких данных об ошибке не было отправлено, этот метод вернет значение null. Это значение по умолчанию.
Итак, если вы не попали на сервер (например, плохой URL) или вы ничего не отправили в ответ, getErrorStream() вернет null.
Ответ 2
InputStream inputStream = null;
try
{
inputStream = connection.getInputStream();
}
catch(IOException exception)
{
inputStream = connection.getErrorStream();
}
Таким образом, это работает для меня. это похоже на то, что когда вы устанавливаете код состояния заголовка ответа как что-либо за пределами 200, объект соединения reset. он генерирует SocketTimeoutException при получении входного потока, но когда он приходит в catch, он все равно дает вам входной поток, что вы ожидаете.
Ответ 3
Копая немного в JDK-код, я наконец нашел причину. HttpURLConnection # getErrorStream() возвращает null при получении 401 или 407, а не потому, что реализация noop в абстрактном классе, а потому, что HttpURLConnection немедленно закрывает/очищает соединение, если видит в режиме потоковой передачи (то есть POST) 401/407. См. Источник конкретной реализации HttpURLConnection: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/sun/net/www/protocol/http/HttpURLConnection.java#1079
Тем не менее, когда вы вызываете IOException при вызове getInputStream(), соединение с сервером уже закрыто, а сокет подчеркивания очищается, поэтому вы всегда получаете null при вызове getErrorStream().
Другие варианты, которые многие предложили, - проверить код состояния перед вызовом getInputStream или getErrorStream. Это не будет для 401 и 407 либо потому, что внутренний errorStream устанавливается только при вызове getInputStream, т.е. Это в основном копия inputStream при статусе кода!= 200. Но опять же, когда вы вызываете getInputStream, соединение будет закрыто.
Ответ 4
Поместите инструкцию conn.setAllowUserInteraction(true);
перед выполнением запроса, и соединение не будет закрыто, даже получив статус 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();