我正在使用apache http client v4.5并将其用作REST客户端。在某些情况下,我识别出一个错误“[读取] I / O错误:读取超时”,它来自httpclient框架,当它读取接收到的内容并将其显示为最后一条消息时。
似乎没有影响,但是我想知道是否有人知道它来自哪里以及如何解决它。根据以下线程(link),似乎是“mutlithreaded”配置的问题。
但是我只使用http客户端的默认配置,当我使用版本v4时,我不知道如何将“multithreaded”设置为false以查看它是否有任何区别。
我也尝试设置超时但没有帮助。
任何提示?
日志:
15:48:05.984 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "HTTP/1.1 200 OK[\r][\n]"
15:48:05.984 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "Date: Tue, 29 Dec 2015 14:48:03 GMT[\r][\n]"
15:48:05.984 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "Server: Apache/2.4.12 (Win32) OpenSSL/1.0.1l PHP/5.6.8[\r][\n]"
15:48:05.984 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "X-Powered-By: PHP/5.6.8[\r][\n]"
15:48:05.985 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "Cache-Control: nocache, private[\r][\n]"
15:48:05.985 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "Content-Length: 99[\r][\n]"
15:48:05.985 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "Keep-Alive: timeout=5, max=99[\r][\n]"
15:48:05.985 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "Connection: Keep-Alive[\r][\n]"
15:48:05.985 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "Content-Type: application/json[\r][\n]"
15:48:05.985 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "[\r][\n]"
15:48:05.985 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "{"success":true,"data":{"id":1946,"location":"http:\/\/localhost:9001\/shop\/api\/articles\/1946"}}"
15:48:06.016 [main] DEBUG org.apache.http.wire - http-outgoing-8 << "[read] I/O error: Read timed out"
我的Http客户端初始化
HttpClientBuilder httpBuilder = HttpClientBuilder.create();
// set timeout did not helped
// RequestConfig.Builder requestBuilder = RequestConfig.custom();
// requestBuilder = requestBuilder.setConnectTimeout(timeout);
// requestBuilder = requestBuilder.setConnectionRequestTimeout(timeout);
// requestBuilder = requestBuilder.setSocketTimeout(timeout);
// httpBuilder.setDefaultRequestConfig(requestBuilder.build());
HttpClient httpClient = httpBuilder.build();
答案 0 :(得分:3)
我使用的是httpclient 4.5.2,在我的情况下,根据请求设置超时有助于:
HttpPost postRequest = new HttpPost("https://...");
postRequest.setHeader(..., ...);
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(1000)
.setConnectTimeout(1000)
.build();
postRequest.setConfig(requestConfig);
答案 1 :(得分:2)
出现此类错误的原因之一可能是服务器在响应后遵循关闭HTTP连接的策略。如果是这种情况,那么可以通过禁用客户端的连接重用来避免此错误,因此客户端不需要验证连接是否仍然存在:
httpBuilder.setConnectionReuseStrategy( (response, context) -> false );
答案 2 :(得分:1)
原因不是“多线程”,而是“ http客户端池”。
这不是错误,只需测试套接字陈旧,当您想重用套接字时就很好。 看到 org / apache / httpcomponents / httpcore / 4.4.10 / httpcore-4.4.10-sources.jar!/org/apache/http/pool/AbstractConnPool.java
for (;;) {
final E leasedEntry = getPoolEntryBlocking(route, state, timeout, tunit, this);
if (validateAfterInactivity > 0) {
if (leasedEntry.getUpdated() + validateAfterInactivity <= System.currentTimeMillis()) {
if (!validate(leasedEntry)) {
leasedEntry.close();
release(leasedEntry, false);
continue;
}
}
}
entryRef.set(leasedEntry);
done.set(true);
onLease(leasedEntry);
if (callback != null) {
callback.completed(leasedEntry);
}
return leasedEntry;
}
protected boolean validate(final CPoolEntry entry) {
return !entry.getConnection().isStale();
}
public boolean isStale() {
if (!isOpen()) {
return true;
}
try {
final int bytesRead = fillInputBuffer(1);
return bytesRead < 0;
} catch (final SocketTimeoutException ex) {
return false;
} catch (final IOException ex) {
return true;
}
}
org / apache / httpcomponents / httpcore / 4.4.10 / httpcore-4.4.10-sources.jar!/org/apache/http/impl/BHttpConnectionBase.java
private int fillInputBuffer(final int timeout) throws IOException {
final Socket socket = this.socketHolder.get();
final int oldtimeout = socket.getSoTimeout();
try {
socket.setSoTimeout(timeout);
return this.inbuffer.fillBuffer();
} finally {
socket.setSoTimeout(oldtimeout);
}
}
将套接字超时设置为1 ms,并读取输入流,返回以下结果:
为避免此消息,只需为validateAfterInactivity设置适当的值,即 客户端套接字超时,保持活动时间(由ConnectionKeepAliveStrategy返回),服务器连接超时以及idleConnectionMonitor的延迟时间的最小值。 这不会检查连接状态,如果重置连接,将创建一个新连接。