有时 HttpURLConnection.getInputStream 执行速度太慢

10
我们有如下代码。
有时我们需要在最后一行等待10-20-40秒。
可能会出现什么问题?
Java 1.4
URL url = ...;
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.connect();
OutputStream out = conn.getOutputStream();
ObjectOutputStream outStream = new ObjectOutputStream(out);
try
{
   outStream.writeObject(objArray);
}
finally
{
   outStream.close();
}

InputStream input = conn.getInputStream();

更新:
下面的代码修复了在ECLIPSE中的问题。
但是它仍然不能通过Java WebStart工作:(

HttpURLConnection conn = (HttpURLConnection) url.openConnection();  
conn.setDoInput(true);  
conn.setDoOutput(true);  
conn.setUseCaches(false);  
System.setProperty("http.keepAlive", "false");  //<---------------
conn.connect();  

但是为什么?

更新一次!
错误已修复!:)

我们在两个类中使用了不同的连接。而第二个类中有以下代码行:

URL url = ...  
HttpURLConnection conn = (HttpURLConnection) url.openConnection();  
conn.setRequestProperty("Content-Length", "1000");  //<------------
conn.connect();  

注意:问题的根源在于setRequestProperty("Content-Length", "1000")


为什么要调用两次 openConnection? - Maurice Perry
这只是打印错误。 已经更正。 - Volodymyr Bezuglyy
为什么Content-Length是个问题呢? - Campa
6个回答

12

我们遇到了类似的问题,是由于旧版Java中有错误的keep-alive引起的。在连接之前添加以下代码以查看是否有所帮助:


加入此句代码
conn.setRequestProperty("Connection", "close");
System.setProperty("http.keepAlive", "false");

第二种方法怎么样?你真的需要发布一个TCP转储来准确地查看问题所在。我不认为这是DNS的问题,因为它发生在connect()调用中。 - ZZ Coder
我觉得keepAlive=false会有所帮助。但是为什么呢? - Volodymyr Bezuglyy
没有任何迹象,我只是在猜测。HTTP请求具有keepalive但没有content-length,服务器不知道请求的结束位置,因此它一直在等待。Apache的默认超时时间为30秒。当关闭keepalive时,OutputStream将被关闭,这会通知服务器请求已完成。 - ZZ Coder
Wireshark/Ethereal、Tcpdump、Snoop。这取决于您的操作系统。 - ZZ Coder
1
设置 connection=close 标头应该可以解决问题。也许您没有正确设置请求属性。这应该在 connect() 之前完成。设置系统属性 http.keepalive=false 基本上是相同的,但作为低级别的解决方法。当未手动指定时,URLConnection 使用它来设置 connection 标头。它在 Webstart 中不起作用只是一个安全限制。但无论如何,setRequestProperty("Connection", "close") 必须有效。请再试一次并验证您是否做对了任何事情。 - BalusC
使用HTTPS可以提高速度,在我的情况下非常有用。 - Virthuss

4
相同的问题,发现是由IPv6引起的。
您可以使用以下代码禁用它:
System.setProperty("java.net.preferIPv4Stack" , "true");

您也可以通过命令行禁用它,使用:g-Djava.net.preferIPv4Stack=true

2

我曾经遇到同样的问题,所以我从Apache改用了HTTPClient,并参照了以下示例:

HttpClient httpClient = HttpClientBuilder.create().build();

HttpPost request = new HttpPost("www.myurl-to-read");

RequestConfig requestConfig = RequestConfig.custom()
                              .setSocketTimeout(8000)
                              .setConnectTimeout(10000)
                              .setConnectionRequestTimeout(1000)
                              .build();

request.setConfig(requestConfig);

request.setHeader("Content-type", "application/json");

HttpResponse  response = httpClient.execute(request);

HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity, "UTF-8");

2

尝试使用IP地址。以查看是否存在DNS问题。


我们在不同的电脑和不同的国家都遇到了这个问题 :( - Volodymyr Bezuglyy
你用Wireshark看过它了吗? - Thomas Jung

1
问题可能来自网络子层...应该很难找到。
但是setReadTimeOut()与较低的值和while循环有何关系?

1

我猜测可能是你的DNS服务器响应不佳。

在开始之前,你可以尝试将符号域名更改为数字IP地址进行实验吗?或者你可以将每个请求重复两次(仅供实验),看第一个请求是否比第二个慢得多?

谷歌已经在8.8.8.8等地方设置了DNS服务器。他们声称它比大多数其他DNS服务器更快。你可以试试看!


我们在不同的电脑和不同的国家都遇到了这个问题 :( - Volodymyr Bezuglyy
在同一家公司?您的私有网络中的DNS可能相同吗? - enguerran
重要的不是你在哪里进行DNS查找,而是哪个DNS服务器处理目标。如果你正在访问一个位于廷巴克图的网站,网络速度很慢等问题可能会出现。在没有查看DNS查找响应时间之前,我不会排除这种可能性。 - Carl Smotricz
生产环境和测试环境是不同的。 - Volodymyr Bezuglyy
我放弃了 - 我无法帮助你。 - Carl Smotricz

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