HttpUrlConnection 中的错误流
我想对我自己编写的 HTTP Servlet 执行 POST 请求。好的情况(HTTP 响应代码 200)使用 URL.openConnection() 方法总是可以正常工作。但是当我收到所需的错误响应代码(例如 400)时,我认为我必须使用 HttpUrlConnection.getErrorStream()。但 ErrorStream 对象为 null,尽管我在错误情况下从 servlet 发送回数据(我想评估此数据以生成错误消息)。 这就是我的代码的样子:
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 (我可以在调用 con.getInputStream() 时抛出的 IOException 中看到它)
谢谢
I want to do a POST request to an HTTP Servlet I wrote myself. Good case (HTTP response Code 200) always works fine by using URL.openConnection() method. But when I receive a desired error response code (e.g. 400) then I thought I have to use HttpUrlConnection.getErrorStream(). But the ErrorStream object is null though I am sending data back from the servlet in error case (I want to evaluate this data to generate error messages).
This is what my code looks like:
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();
}
So my question is, why returns getErrorStream() null though status code is 400 (I can see it in the IOException that is thrown when it calls con.getInputStream())
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
在执行请求之前添加语句conn.setAllowUserInteraction(true);,即使收到401状态,连接也不会关闭。
Put the statement
conn.setAllowUserInteraction(true);
before execute the request and the connection will not be closed, even receiving 401 status.正如 Android 文档中建议的那样:
As suggested in the Android documentation:
来自关于 getErrorStream() 的 java 文档:
因此,如果您没有到达服务器(例如错误的 url)或者服务器没有在响应中发送任何内容,getErrorStream() 将返回 null。
From the java documentation on getErrorStream():
So if you didn't get to the server (bad url for example) or the server didn't send anything in the response, getErrorStream() will return null.
就像当您将响应标头状态代码设置为超过 200 时,连接对象将被重置。它会在获取输入流时生成 SocketTimeoutException ,但是当它进入 catch 时,无论如何它都会为您提供输入流,这是您所期望的。
It is like when you set response header status code as anything beyond 200, the connection object is reset. it will generate SocketTimeoutException while getting the inputstream but when it comes in the catch it gives you the inputstream anyway, what you are expecting.
深入研究了一下JDK代码,终于找到了原因。 HttpURLConnection#getErrorStream() 在收到 401 或 407 时返回 null,不是因为抽象类中的 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
也就是说,当你在调用 getInputStream() 时捕获 IOException 时,与服务器的连接已经关闭,并且下划线套接字也被清除,因此在调用 getErrorStream() 时你总是会得到 null。
许多人建议的其他选项是在调用 getInputStream 或 getErrorStream 之前检查状态代码。这对于 401 和 407 也不会,因为内部 errorStream 仅在您调用 getInputStream 时设置,即,当状态代码 != 200 时,它基本上是 inputStream 的副本。但是当您调用 getInputStream 时,连接将被关闭。
Digging a little bit into JDK code, I finally find the reason. HttpURLConnection#getErrorStream() returns null when receiving a 401 or 407, not because the noop implementation in the abstract class, but because HttpURLConnection closes/clears the connection immediately if it sees a 401/407 when in streaming mode(i.e., POST). See the source of the concrete implementation of HttpURLConnection: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/sun/net/www/protocol/http/HttpURLConnection.java#1079
That said, when you catch an IOException when calling getInputStream(), the connection to server is already closed and the underlining socket is cleared, so you would always get null when calling getErrorStream().
The other options many have suggested is to check the status code before calling getInputStream or getErrorStream. This won't for 401 and 407 either because the internal errorStream is only set when you call getInputStream, i.e., it's a basically a copy of the inputStream when status code != 200. But again when you call getInputStream, the connection will be closed.