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

Che*_*eng 7 android

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

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
        }
}
Run Code Online (Sandbox Code Playgroud)

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

Man*_*ani 6

如果你不感兴趣的显示错误信息给用户,关闭InputStream或调用disconnectHttpURLConnectionfinally块不读的错误消息.这是您在大多数示例中看到的内容.

在浏览HttpURLConnection的实现时,我在其中一个源代码中遇到了以下注释.这可能是连接在没有读取所有数据的情况下关闭的原因.

当连接意外关闭以使高速缓存条目无效并防止重用HTTP连接时,应调用此方法.HTTP消息是串行发送的,因此无论何时消息都无法读取完成,也无法读取后续消息,必须丢弃连接.

根据Android的实现HttpURLConnection,万一例外:

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

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

在此输入图像描述

代码分析:让我们看看FixedLengthInputStream的一个专门InputStream实现.这是close方法实现:

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

实例变量bytesRemaining包含仍待InputStream读取的字节数.这是unexpectedEndOfInput方法实现:

protected final void unexpectedEndOfInput() {
    if (cacheRequest != null) {
        cacheRequest.abort();
    }
    httpEngine.release(false);
}
Run Code Online (Sandbox Code Playgroud)

这是发布方法实现.调用disconnectHttpURLConnection情况下会导致调用此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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您共享的代码,在其中处理IOException,读取错误流然后关闭,确保Connection可重用并添加到连接池.所有的数据读取瞬间InputStreamConnection被添加到连接池.以下是read方法实现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;
    }
Run Code Online (Sandbox Code Playgroud)

bytesRemaining变量变为0时,调用endOfInput,这将进一步调用releasetrue参数的方法,这将确保连接被合并.

protected final void endOfInput(boolean reuseSocket) throws IOException {
        if (cacheRequest != null) {
            cacheBody.close();
        }
        httpEngine.release(reuseSocket);
    }
Run Code Online (Sandbox Code Playgroud)