【问题标题】:How to gracefully clean up an HTTPURLConnection when an exception is caught?捕获异常时如何优雅地清理 HTTPURLConnection?
【发布时间】:2012-02-23 17:52:17
【问题描述】:

我有一个 Java 小程序,它使用 HTTPURLConnection 类将非常大的文件上传到 IIS-7 网络服务器。小程序将文件分块,然后使用固定长度流将这些片段发布到 PHP 脚本。

有时,在上传文件块时,客户端和服务器之间的网络连接会莫名其妙地断开。发生这种情况时,我对 writeBytes() 方法的调用会引发我捕获的 IOException。捕捉到这个异常后,我进入我的finally 块,在那里我尝试清理东西。由于写入连接的数据不足(请记住,这是固定长度的流式传输),关闭输出流的尝试也会失败。结果,连接似乎“保持不变”(即底层套接字保持打开状态)。这似乎可以通过查看 StreamingOutputStream 类的 source codeclose() 方法来验证(注意说明套接字无法关闭的注释)。

问题:

在写到HTTPURLConnection 时,有没有一种优雅的方式可以在捕获IOException 后关闭?将HTTPURLConnection 对象告诉disconnect() 似乎还不够好。

附加信息:

这是我在调用HTTPURLConnection 类的writeBytes() 方法时引发的第一个异常:

java.io.IOException: Error writing request body to server
    at sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream.checkError(Unknown Source)
    at sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream.write(Unknown Source)
    at java.io.DataOutputStream.write(Unknown Source)
    at MultiPartPostThread.run(MultiPartPostThread.java:321)

我捕获了这个异常,然后尝试关闭我用来写入连接的DataOutputStream 对象。当我这样做时,我得到了这个异常:

java.io.IOException: insufficient data written
    at sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream.close(Unknown Source)
    at java.io.FilterOutputStream.close(Unknown Source)
    at MultiPartPostThread.run(MultiPartPostThread.java:370)

我可以通过注意到失败条目在 IIS 日志中显示需要 10 分钟来验证套接字是否保持打开状态。该延迟(10 分钟)恰好是我的连接超时值。 IIS 日志中的示例行(为简洁起见):

2012-01-31 20:20:07 POST /upload_handler.php 200 0 0 356 26215490 3666
2012-01-31 20:20:10 POST /upload_handler.php 200 0 0 356 26215490 3853
2012-01-31 20:30:22 POST /upload_handler.php 500 0 64 0 15286099 611442

请注意,在日志的前两行中,我们进行了很好的传输:每次发送 25 MB,并返回 200 状态代码。然后在上次成功传输 10 分钟后出现故障,并出现无用的错误 500(请注意,这只是部分传输;仅传输了约 15MB)。实际上,这种神秘的断开连接发生在整个过程大约 1 分钟,所以我在 IIS 跟踪日志中看到的超时消息是红鲱鱼。我在我的 PHP 日志、HTTPERR 日志或服务器上的系统日志中看不到任何有用的信息。

【问题讨论】:

    标签: java exception-handling applet httpurlconnection


    【解决方案1】:

    在您的流上调用 close() 应该释放

    使用的资源
    HTTPURLConnection 
    

    这是来自 HTTPURLConnection javadoc 的注释

    在请求后对 HttpURLConnection 的 InputStream 或 OutputStream 调用 close() 方法可能会释放与此实例关联的网络资源,但不会影响任何共享的持久连接。如果持续连接当时处于空闲状态,则调用 disconnect() 方法可能会关闭底层套接字。

    【讨论】:

    • 问题是close() 调用本身会抛出异常(即没有成功)。这是对写入抛出的 IOException 的补充。
    • 那么唯一的选择就是disconnect()。您可以查看这个有趣的 SO 讨论 stackoverflow.com/questions/4767553/…
    • 我将断开连接称为我最终清理的一部分。这似乎没有奏效。可能是我没有适当的访问权限来解决这个问题......
    【解决方案2】:

    我对此进行的研究越多,我就越确信无法进行优雅的清理。 disconnect() 调用似乎不足以关闭底层套接字;您只需等待它超时。

    我想我会尝试使用Apache HttpComponents HttpClient(在此terrific SO wiki post 底部推荐),看看它的内置错误处理是否可以处理我看到的这种奇怪的情况。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-10-02
      • 2014-07-10
      • 2015-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多