【发布时间】:2015-04-18 05:44:56
【问题描述】:
我第一次使用 Apache HttpComponents,特别是 HttpClient。我有一个相当基本的用例。我每 N 秒轮询一次第三方服务器(在这种情况下,他们的 API 需要 POST)。
CloseableHttpClient httpclient = HttpClients.custom().
setDefaultCookieStore(cookieStore).build();
然后我在循环中执行一些 POST 请求...使用:
while (!someCondition) {
HttpPost httpPost = ...
httpclient.execute(httpPost)
Thread.sleep(SOME_TIME)
}
我注意到如果我睡了更长的时间,比如 3 分钟,那么我就没有从服务器得到响应,并且每次连接都会中断:
DEBUG [org.apache.http.wire] http-outgoing-1 << "end of stream"
DEBUG [org.apache.http.impl.conn.DefaultManagedHttpClientConnection] http-outgoing-1: Close connection
DEBUG [org.apache.http.impl.conn.DefaultManagedHttpClientConnection] http-outgoing-1: Shutdown connection
DEBUG [org.apache.http.impl.execchain.MainClientExec] Connection discarded
DEBUG [org.apache.http.impl.conn.DefaultManagedHttpClientConnection] http-outgoing-1: Close connection
我不相信它是服务器。我可能没有正确使用 HttpComponents,或者我的配置错误。如果我将其设置为较短的持续时间(例如 1 分钟),它可以正常工作(我确实注意到它在运行约 15 分钟后死亡 - 所以这是 15 个一分钟的间隔)。
为了发送请求,我将它包装在一些 Java 8 lambda 中并使用资源尝试,但我认为这并不重要:
private <R> R sendRequest(HttpUriRequest request, Function<String, R> func) {
try {
try (CloseableHttpResponse resp = this.httpclient.execute(request)) {
HttpEntity entity = resp.getEntity();
String responseString = EntityUtils.toString(entity);
R result = null;
if (func != null) {
result = func.apply(responseString);
}
EntityUtils.consume(entity);
return result;
}
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Error sending request: " + request, e);
}
}
实际的例外是:
Caused by: org.apache.http.NoHttpResponseException: myserver.com:80 failed to respond
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:143)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:57)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:261)
at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:165)
at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:167)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:272)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:124)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:271)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)
【问题讨论】:
-
您显示的最后一个异常真的是异常的根本原因吗? Java的网络层什么都没有(IOException?)
-
我相信是的。它目前已经运行了大约 25 分钟(大约 30 秒的睡眠时间),所以我现在不想杀死它。但我会跟进。
-
你的客户端和http服务器之间有防火墙吗?
-
如果您在日志中看到 'http-outgoing-1
-
@oleg 我明白这似乎正在发生。我不明白为什么如果我创建一个 HttpClient 实例,发送一个请求,等待 3 分钟,然后发送另一个请求,每次都会失败。但如果我改为睡 30 秒左右,它可以正常运行近 2 小时。每次我想发送请求时,我是否应该创建一个新的 HttpClient 实例?我假设我可以拥有一个实例,它为我管理池连接、处理重试等(因为我使用的是那些默认配置)。
标签: java apache-httpclient-4.x apache-httpcomponents