抛出IOException时是否需要使用HttpURLConnection的错误流

时间:2014-04-17 14:51:26

标签: android

根据Oracle Java的技术指南,我们应该在HttpURLConnection抛出时消耗IOException的错误流

http://docs.oracle.com/javase/6/docs/technotes/guides/net/http-keepalive.html

  

你可以做些什么来帮助Keep-Alive?不要放弃连接   通过忽略响应主体。这样做可能会导致TCP空闲   连接。当它们不是时,需要进行垃圾收集   更长的参考。

     

如果getInputStream()成功返回,请读取整个响应   体。

     

从HttpURLConnection调用getInputStream()时,如果是   发生IOException,捕获异常并调用getErrorStream()   得到响应主体(如果有的话)。

     

即使您没有,阅读响应正文也会清除连接   对响应内容本身感兴趣。但如果反应机构是   看到之后,你对其余部分并不感兴趣   一开始,你可以关闭InputStream。但你需要注意   更多的数据可能会在路上。因此连接可能不是   清除再利用。

     

这是符合上述建议的代码示例:

这是代码示例

try {
        URL a = new URL(args[0]);
        URLConnection urlc = a.openConnection();
        is = conn.getInputStream();
        int ret = 0;
        while ((ret = is.read(buf)) > 0) {
          processBuf(buf);
        }
        // close the inputstream
        is.close();
} catch (IOException e) {
        try {
                respCode = ((HttpURLConnection)conn).getResponseCode();
                es = ((HttpURLConnection)conn).getErrorStream();
                int ret = 0;
                // read the response body
                while ((ret = es.read(buf)) > 0) {
                        processBuf(buf);
                }
                // close the errorstream
                es.close();
        } catch(IOException ex) {
                // deal with the exception
        }
}

这适用于Android平台吗?因为我在大多数Android代码示例中都没有看到这样的技术。

2 个答案:

答案 0 :(得分:6)

如果您不想向用户显示错误消息,请关闭InputStream或在disconnect块中的HttpURLConnection上调用finally,而不会阅读错误消息。这是你在大多数例子中看到的。

在浏览HttpURLConnection的实现时,我在其中一个source code中发现了以下评论。这可能就是为什么在没有读取所有数据的情况下关闭连接的原因。

  

当连接意外关闭时应调用此方法   使缓存条目无效并阻止HTTP连接   被重用。无论何时消息,HTTP消息都是串行发送的   无法读取完成,后续消息无法读取   或者必须丢弃连接。

根据Android的HttpURLConnection实现,如果发生异常:

  • 如果未读取错误且InputStream已关闭,则连接将被视为不可重复使用并关闭。
  • 如果您读取错误然后关闭InputStream,则连接被视为可重复使用,并被添加到连接池中。

您可以在下图中看到变量connection&读取所有数据后,connectionReleased分别设置为nulltrue。请注意,getErrorStream会返回InputStream,因此它在异常情况下也有效。

enter image description here

代码分析:让我们看一下FixedLengthInputStream专门的InputStream实现。以下是close方法实现:

 @Override public void close() throws IOException {
    if (closed) {
        return;
    }
    closed = true;
    if (bytesRemaining != 0) {
        unexpectedEndOfInput();
    }
 }

实例变量bytesRemaining包含要读取的InputStream上仍可用的字节数。以下是unexpectedEndOfInput方法实现:

protected final void unexpectedEndOfInput() {
    if (cacheRequest != null) {
        cacheRequest.abort();
    }
    httpEngine.release(false);
}

这是release方法实现。在disconnect实例上调用HttpURLConnection会导致调用此release方法,并将false作为参数。 最后一次if检查可确保是否需要关闭连接或将其添加到连接池以供重复使用。

public final void release(boolean reusable) {
    // If the response body comes from the cache, close it.
    if (responseBodyIn == cachedResponseBody) {
        IoUtils.closeQuietly(responseBodyIn);
    }
    if (!connectionReleased && connection != null) {
        connectionReleased = true;
        // We cannot reuse sockets that have incomplete output.
        if (requestBodyOut != null && !requestBodyOut.closed) {
            reusable = false;
        }
        // If the headers specify that the connection shouldn't be reused, don't reuse it.
        if (hasConnectionCloseHeader()) {
            reusable = false;
        }
        if (responseBodyIn instanceof UnknownLengthHttpInputStream) {
            reusable = false;
        }
        if (reusable && responseBodyIn != null) {
            // We must discard the response body before the connection can be reused.
            try {
                Streams.skipAll(responseBodyIn);
            } catch (IOException e) {
                reusable = false;
            }
        }
        if (!reusable) {
            connection.closeSocketAndStreams();
            connection = null;
        } else if (automaticallyReleaseConnectionToPool) {
            HttpConnectionPool.INSTANCE.recycle(connection);
            connection = null;
        }
    }
}

您共享的代码,在其中处理IOException,读取错误流然后关闭,确保Connection可重用并添加到连接池。从InputStream读取所有数据的那一刻,Connection被添加到连接池。以下是read的{​​{1}}方法实现:

FixedLengthInputStream

@Override public int read(byte[] buffer, int offset, int count) throws IOException { Arrays.checkOffsetAndCount(buffer.length, offset, count); checkNotClosed(); if (bytesRemaining == 0) { return -1; } int read = in.read(buffer, offset, Math.min(count, bytesRemaining)); if (read == -1) { unexpectedEndOfInput(); // the server didn't supply the promised content length throw new IOException("unexpected end of stream"); } bytesRemaining -= read; cacheWrite(buffer, offset, read); if (bytesRemaining == 0) { endOfInput(true); } return read; } 变量变为0时,将调用endOfInput,这将使用bytesRemaining参数进一步调用release方法,这将确保合并连接。

true

答案 1 :(得分:0)

如果它是针对Java记录的,那么它就是对Android平台的绑定。