HttpUrlConnection 中的错误流

发布于 2024-11-08 15:14:15 字数 1691 浏览 0 评论 0原文

我想对我自己编写的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

硪扪都還晓 2024-11-15 15:14:16

在执行请求之前添加语句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();

Put the statement conn.setAllowUserInteraction(true); before execute the request and the connection will not be closed, even receiving 401 status.

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();
鼻尖触碰 2024-11-15 15:14:16

正如 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();
}

As suggested in the Android documentation:

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();
}
看透却不说透 2024-11-15 15:14:15

来自关于 getErrorStream() 的 java 文档:

如果连接失败但服务器仍然发送了有用的数据,则返回错误流。典型的例子是,当 HTTP 服务器响应 404 时,这将导致在连接中抛出 FileNotFoundException,但服务器发送了一个 HTML 帮助页面,其中包含有关如何操作的建议。
此方法不会导致连接启动。 如果连接未连接,或者服务器在连接时没有发生错误,或者服务器发生错误但没有发送错误数据,则此方法将返回 null。 这是默认值。

因此,如果您没有到达服务器(例如错误的 url)或者服务器没有在响应中发送任何内容,getErrorStream() 将返回 null。

From the java documentation on getErrorStream():

Returns the error stream if the connection failed but the server sent useful data nonetheless. The typical example is when an HTTP server responds with a 404, which will cause a FileNotFoundException to be thrown in connect, but the server sent an HTML help page with suggestions as to what to do.
This method will not cause a connection to be initiated. If the connection was not connected, or if the server did not have an error while connecting or if the server had an error but no error data was sent, this method will return null. This is the default.

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.

撕心裂肺的伤痛 2024-11-15 15:14:15
InputStream inputStream = null;     
try {
    inputStream = connection.getInputStream();
} catch(IOException exception) {
   inputStream = connection.getErrorStream();
}

就像当您将响应标头状态代码设置为超过 200 时,连接对象将被重置。它会在获取输入流时生成 SocketTimeoutException ,但是当它进入 catch 时,无论如何它都会为您提供输入流,这是您所期望的。

InputStream inputStream = null;     
try {
    inputStream = connection.getInputStream();
} catch(IOException exception) {
   inputStream = connection.getErrorStream();
}

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.

似最初 2024-11-15 15:14:15

深入研究了一下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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文