HttpURLConnection的getInputStream方法:180秒后总是超时

8

我正在尝试在非常慢的连接中以以下方式下载文件:

    java.net.URL url = new URL("https://X.X.X.X:8443/path/2f6b88cf2b70ee933197edfc9627a9bc/");
    HttpURLConnection connection = (HttpURLConnection)  url.openConnection();
    connection.setRequestMethod("GET");
    connection.setDoOutput(true);
    connection.setConnectTimeout(240 * 1000);
    connection.setReadTimeout(240 * 1000);
    long start = System.currentTimeMillis();
    Files.copy(connection.getInputStream(), new File("test.zip").toPath());
    System.out.println("Time: "+((System.currentTimeMillis() - start) / 1000) + " sec.");

我注意到在下载时总是在180秒后中断,可能是因为本机Windows套接字超时原因。设置setConnectTimeout(...)或setReadTimeout(...)的超时时间并不能解决问题。

我尝试使用wget下载该文件:

wget https://X.X.X.X:8443/path/2f6b88cf2b70ee933197edfc9627a9bc/ --no-check-certificate
--2015-09-07 14:36:12--  https://X.X.X.X:8443/path/2f6b88cf2b70ee933197edfc9627a9bc/
Connecting to X.X.X.X:8443... connected.
WARNING: The certificate of ‘X.X.X.X’ is not trusted.
WARNING: The certificate of ‘X.X.X.X’ hasn't got a known issuer.
The certificate's owner does not match hostname ‘X.X.X.X’
HTTP request sent, awaiting response... 302 Found
Location: https://X.X.X.X:8443/files/test.zip [following]
--2015-09-07 14:36:16--  https://X.X.X.X:8443/files/test.zip
Reusing existing connection to X.X.X.X:8443.
HTTP request sent, awaiting response... 200 OK
Length: 321917584 (307M) [application/zip]
Saving to: ‘test.zip’

test.zip                                  100%[====================================================================================>] 307.00M   253KB/s   in 19m 50ss

完整文件在20分钟后成功保存在磁盘上。

HttpURLConnection有什么问题?

编辑: 我尝试通过HTTP协议从其他服务器下载测试文件,一切正常。看起来是一个特定于服务器或协议的问题。但是为什么wget可以下载整个文件呢?

编辑2:根据您的建议,我还尝试了以下操作:

  • 删除connection.setDoOutput(true);
  • 使用直接链接以避免重定向302
  • 使用自定义实现替换Files.copy方法

不幸的是,以上操作都没有帮助。

编辑3: 我注意到文件也可以通过不安全的HTTP协议在同一台服务器上获得。所以我只改变了代码中的URL,在120秒后得到了结果:

Exception in thread "main" java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(SocketInputStream.java:196)
    at java.net.SocketInputStream.read(SocketInputStream.java:122)
    at java.io.BufferedInputStream.read1(BufferedInputStream.java:273)
    at java.io.BufferedInputStream.read(BufferedInputStream.java:334)
    at sun.net.www.MeteredStream.read(MeteredStream.java:134)
    at java.io.FilterInputStream.read(FilterInputStream.java:133)
    at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3066)
    at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3060)
    at java.nio.file.Files.copy(Files.java:2735)
    at java.nio.file.Files.copy(Files.java:2854) 

我对readTimeout的理解是等待数据可用的时间。不管怎样,它们是以毫秒为单位的,而你给出了240,000 - 4分钟。 - Dakshinamurthy Karra
@LittleSanti 我应该提到没有任何异常。程序正常退出。 - Tomasz Ceszke
1
从wget输出中可以看到有一个302重定向。你能否尝试使用重定向后的URL并查看发生了什么?@tomek.ceszke - Dakshinamurthy Karra
@KDM 刚刚检查了一下,没有帮助。HttpURLConnection 正确地遵循重定向。 - Tomasz Ceszke
1
@tomek.ceszke 这段代码是你正在尝试的一个独立程序还是一个更大的程序的一部分?Files.copy 返回复制的字节数。你能打印出这个值吗? - Dakshinamurthy Karra
显示剩余4条评论
2个回答

2

我最终在这里找到了一个解决方案(再次感谢StackOverflow)。问题出在服务器端。

我们使用的Jetty 9.2存在一个bug,会在慢速连接上中断传输大文件(https://bugs.eclipse.org/bugs/show_bug.cgi?id=472621)。看起来异常并不总是被抛出。

无论如何,Wget和浏览器都能够在传输停滞或连接重置的情况下完成下载。不幸的是,我的Java应用程序更为敏感......

升级捆绑的Jetty到最新的稳定版本9.3.3可以解决所有下载问题。


0
connection.setRequestMethod("GET");

你打算进行一个HTTP GET请求。

connection.setDoOutput(true);

这里你要把它改为PUT。

Files.copy(connection.getInputStream(), new File("test.zip").toPath());

在这里,您可以获取输入流而无需编写任何内容。服务器仍在等待您从未发送的POST数据,因此它永远不会发送响应,因此您会超时。

删除setDoOutput(true);行。


谢谢您的回答,但是没有帮助到我。 - Tomasz Ceszke
你需要展示你所做的事情。将其编辑到你的问题中。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接