Apache Http Client打印“[read] I / O错误:读取超时”“

时间:2015-12-29 15:13:01

标签: java multithreading timeout httpclient apache-httpcomponents

我正在使用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();

3 个答案:

答案 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,并读取输入流,返回以下结果:

  1. -1重新创建新连接
  2. “> 0”重用连接
  3. 超时异常,重用连接
  4. IO异常重新创建新连接

为避免此消息,只需为validateAfterInactivity设置适当的值,即 客户端套接字超时,保持活动时间(由ConnectionKeepAliveStrategy返回),服务器连接超时以及idleConnectionMonitor的延迟时间的最小值。 这不会检查连接状态,如果重置连接,将创建一个新连接。