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

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

What can you do to help with Keep-Alive? Do not abandon a connection
by ignoring the response body. Doing so may results in idle TCP
connections. That needs to be garbage collected when they are no
longer referenced.

If getInputStream() successfully returns,read the entire response
body.

When calling getInputStream() from HttpURLConnection,if an
IOException occurs,catch the exception and call getErrorStream() to
get the response body (if there is any).

Reading the response body cleans up the connection even if you are not
interested in the response content itself. But if the response body is
long and you are not interested in the rest of it after seeing the
beginning,you can close the InputStream. But you need to be aware
that more data Could be on its way. Thus the connection may not be
cleared for reuse.

Here’s a code example that complies to the above recommendation:

这是代码示例

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代码示例中都没有看到这样的技术.

解决方法

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

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

This should be invoked when the connection is closed unexpectedly to
invalidate the cache entry and to prevent the HTTP connection from
being reused. HTTP messages are sent in serial so whenever a message
cannot be read to completion,subsequent messages cannot be read
either and the connection must be discarded.

根据Android的HttpURLConnection实现,如遇异常:

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

您可以在下图中看到可变连接&只要读取所有数据,connectionReleased分别设置为null和true.请注意,getErrorStream返回InputStream,因此它在异常场景中也是有效的.

代码分析:让我们看看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方法实现.在HttpURLConnection实例上调用disconnect将导致调用此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将添加到连接池中.这是FixedLengthInputStream的read方法实现:

@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,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,read);
        if (bytesRemaining == 0) {
            endOfInput(true);
        }
        return read;
    }

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

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

android – 抛出IOException时我们是否需要使用HttpURLConnection的错误流的更多相关文章

  1. android – 如何实现消息读取状态,如whatsapp蓝色刻度?

    我正在开发一个应用程序,聊天是一个模块,聊天我正在使用xmpp.当我发送消息时,我使用DeliveryReceiptManager获取该消息传递状态.但我需要表明该消息是用户READ或NOTwhatsApp蓝色tickmark,任何人都可以帮助我,我被击中了.如何实现此消息读取概念.提前致谢.解决方法创建自定义数据包扩展类当进入聊天列表时发送具有相同包ID的消息标签其中mConnection是xm

  2. 如何在Android上解锁InputStream.read()?

    我有一个线程,其中在循环中调用InputStream的read()方法.当没有更多字节要读取时,流将阻塞,直到新数据到达.如果我从另一个线程调用InputStream上的close(),则流将关闭,但阻塞的read()调用仍然被阻止.我假设read()方法现在应该以值-1返回以指示流的结束,但它不会.相反,它会被阻塞几分钟,直到发生tcp超时.如何取消阻止close()调用?

  3. android – 抛出IOException时我们是否需要使用HttpURLConnection的错误流

    根据OracleJava的技术指南,我们应该在抛出IOException时使用HttpURLConnection的错误流http://docs.oracle.com/javase/6/docs/technotes/guides/net/http-keepalive.htmlWhatcanyoudotohelpwithKeep-Alive?Donotabandonaconnectionbyignor

  4. 如何从蓝牙条码扫描器读取数据符号CS3070到Android设备

    在我的项目中,我必须使用条形码扫描器SymbolCS3070通过蓝牙阅读条形码.即;我必须通过蓝牙建立Android设备和条码扫描器之间的连接.任何人都可以告诉我如何从条形码阅读器读取值,以及如何设置通信?>>首先,您必须扫描手册中的“串行端口配置文件”中的条形码.这是我工作代码的不完整版本,但你应该得到要点.我希望这个解决方案也适合你!

  5. python文件读取read及readlines两种方法使用详解

    这篇文章主要为大家介绍了python文件读取read及readlines两种方法的使用示例及区别详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  6. jQuery 出现Cannot read property ‘msie’ of undefined错误的解决方法

    这篇文章主要介绍了jQuery 出现Cannot read property ‘msie’ of undefined错误的解决方法的相关资料,需要的朋友可以参考下

  7. jQuery的Read()方法代替原生JS详解

    众所周知在jQuery中ready方法在DOM完全下载后立即执行其中的代码。因为它是等所有的DOM元素都加载完毕,才执行给定的函数,所以你能确定那些试图操作和访问元素节点的方法都能被执行。而这篇文章给大家介绍的是如何用jQuery的Read()方法代替原生JS,下面来一起看看。

  8. python面试题之read、readline和readlines的区别详解

    当python进行文件的读取会遇到三个不同的函数,它们分别是read(),readline(),和readlines(),下面这篇文章主要给大家介绍了关于python面试题之read、readline和readlines区别的相关资料,需要的朋友可以参考下

  9. Windows和Linux之间Java套接字的差异 – 如何处理它们?

    为什么在Linux上这些例外不会在Windows上被抛出?

  10. 分段错误:当bufffer> 4M时,在Ubuntu中的C程序中进行堆栈分配

    ,2^i,其中i=0..30这是我如何编译它的一个例子:gcc-DBUFFERSIZE=8388608prog_sys.c-obin/psys.8M问题:在我的机器中,该程序的所有版本都可以正常工作:./psys.1M

随机推荐

  1. bluetooth-lowenergy – Altbeacon库无法在Android 5.0上运行

    昨天我在Nexus4上获得了Android5.0的更新,并且altbeacon库停止了检测信标.似乎在监视和测距时,didEnterRegion和didRangeBeaconsInRegion都没有被调用.即使RadiusNetworks的Locate应用程序现在表现不同,一旦检测到信标的值,它们就不再得到更新,并且通常看起来好像信标超出了范围.我注意到的一点是,现在在logcat中出现以下行“B

  2. android – react-native动态更改响应者

    我正在使用react-native进行Android开发.我有一个视图,如果用户长按,我想显示一个可以拖动的动画视图.我可以使用PanResponder实现这一点,它工作正常.但我想要做的是当用户长按时,用户应该能够继续相同的触摸/按下并拖动新显示的Animated.View.如果您熟悉Google云端硬盘应用,则它具有类似的功能.当用户长按列表中的任何项目时,它会显示可拖动的项目.用户可以直接拖

  3. android – 是否有可能通过使用与最初使用的证书不同的证书对其进行签名来发布更新的应用程序

    是否可以通过使用与最初使用的证书不同的证书进行签名来发布Android应用程序的更新?我知道当我们尝试将这样的构建上传到市场时,它通常会给出错误消息.但有没有任何出路,比如将其标记为主要版本,指定市场中的某个地方?解决方法不,你不能这样做.证书是一种工具,可确保您是首次上传应用程序的人.所以总是备份密钥库!

  4. 如何检测Android中是否存在麦克风?

    ..所以我想在让用户访问语音输入功能之前检测麦克风是否存在.如何检测设备上是否有麦克风.谢谢.解决方法AndroidAPI参考:hasSystemFeature

  5. Android – 调用GONE然后VISIBLE使视图显示在错误的位置

    我有两个视图,A和B,视图A在视图B上方.当我以编程方式将视图A设置为GONE时,它将消失,并且它正下方的视图将转到视图A的位置.但是,当我再次将相同的视图设置为VISIBLE时,它会在视图B上显示.我不希望这样.我希望视图B回到原来的位置,这是我认为会发生的事情.我怎样才能做到这一点?编辑–代码}这里是XML:解决方法您可以尝试将两个视图放在RelativeLayout中并相对于彼此设置它们的位置.

  6. android – 获得一首歌的流派

    我如何阅读与歌曲相关的流派?我可以读这首歌,但是如何抓住这首歌的流派,它存放在哪里?解决方法检查此代码:

  7. android – 使用textShadow折叠工具栏

    我有一个折叠工具栏的问题,在展开状态我想在文本下面有一个模糊的阴影,我使用这段代码:用:我可以更改textColor,它可以工作,但阴影不起作用.我为阴影尝试了很多不同的值.是否可以为折叠文本投射阴影?

  8. android – 重用arm共享库

    我已经建立了armarm共享库.我有兴趣重用一个函数.我想调用该函数并获得返回值.有可能做这样的事吗?我没有任何头文件.我试过这个Android.mk,我把libtest.so放在/jni和/libs/armeabi,/lib/armeabi中.此时我的cpp文件编译,但现在是什么?我从objdump知道它的名字编辑:我试图用这个android.mk从hello-jni示例中添加prebuild库:它工作,但libtest.so相同的代码显示以下错误(启动时)libtest.so存在于libhello-j

  9. android – 为NumberPicker捕获键盘’Done’

    我有一个AlertDialog只有一些文本,一个NumberPicker,一个OK和一个取消.(我知道,这个对话框还没有做它应该保留暂停和恢复状态的事情.)我想在软键盘或其他IME上执行“完成”操作来关闭对话框,就像按下了“OK”一样,因为只有一个小部件可以编辑.看起来处理IME“Done”的最佳方法通常是在TextView上使用setonEditorActionListener.但我没有任何Te

  10. android – 想要在调用WebChromeClient#onCreateWindow时知道目标URL

    当我点击一个带有target=“_blank”属性的超链接时,会调用WebChromeClient#onCreateWindow,但我找不到新的窗口将打开的新方法?主页url是我唯一能知道的东西?我想根据目标网址更改应用行为.任何帮助表示赞赏,谢谢!

返回
顶部