HttpUrlConnection中的错误流

问题描述 投票:17回答:5

我想对我自己编写的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中看到它)

谢谢

httpurlconnection
5个回答
19
投票

来自getErrorStream()的java文档:

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

因此,如果您没有访问服务器(例如,错误的URL)或服务器未在响应中发送任何内容,则getErrorStream()将返回null。


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

就像将响应头状态代码设置为超过200的任何内容一样,连接对象将被重置。它会在获取输入流时生成SocketTimeoutException,但是当它进入catch时它会为你提供输入流,无论如何,你期望的是什么。


8
投票

深入研究一下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时,连接将被关闭。


3
投票

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

0
投票

正如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();
}
© www.soinside.com 2019 - 2024. All rights reserved.