java Apache Http 客户端打印“[读取] I/O 错误:读取超时””

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34513826/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 22:59:20  来源:igfitidea点击:

Apache Http Client prints "[read] I/O error: Read timed out""

javamultithreadingtimeouthttpclientapache-httpcomponents

提问by megloff

I am using apache http client v4.5 and using it as a REST client. In some cases I recognize an error "[read] I/O error: Read timed out" which comes from the httpclient framework when it reads the received content and shows it as a last message.

我正在使用 apache http 客户端 v4.5 并将其用作 REST 客户端。在某些情况下,当 httpclient 框架读取接收到的内容并将其显示为最后一条消息时,我会识别出错误“[read] I/O error: Read timed out”。

It seems not to have an impact, however I wonder if somebody has an idea where it is coming from and how it can be solved. According the following thread (link) it seems to be an issue with the "mutlithreaded" configuration.

它似乎没有影响,但是我想知道是否有人知道它来自哪里以及如何解决它。根据以下线程(链接),“mutlithreaded”配置似乎存在问题。

However I use only the default configuration of http client and while I am using the version v4 I have no clue how I can set "multithreaded" to false to see if it makes any difference.

但是,我仅使用 http 客户端的默认配置,并且在使用 v4 版本时,我不知道如何将“多线程”设置为 false 以查看它是否有任何区别。

I also tried to set the timeouts but it did not helped.

我也尝试设置超时,但没有帮助。

Any hints?

任何提示?

Log:

日志:

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"

my Http client initialization

我的 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();

回答by Ivan Hristov

I'm using httpclient 4.5.2 and in my case, setting the timeouts on a request helped:

我正在使用 httpclient 4.5.2,就我而言,在请求上设置超时有帮助:

HttpPost postRequest = new HttpPost("https://...");
postRequest.setHeader(..., ...);

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

postRequest.setConfig(requestConfig);

回答by Sergey Ushakov

One of the reasons for having such an error may be that the server follows the policy of closing HTTP connections upon having responded. If that is the case, then this error may be avoided by disabling connection reuse by the client, so there would be no need for the client to verify that the connection is still alive:

出现此类错误的原因之一可能是服务器在响应时遵循关闭 HTTP 连接的策略。如果是这种情况,则可以通过禁用客户端的连接重用来避免此错误,因此客户端无需验证连接是否仍然存在:

httpBuilder.setConnectionReuseStrategy( (response, context) -> false );

回答by avatas

The reason is not "multithread", but "http client Pool".

原因不是“多线程”,而是“http 客户端池”。

It is not a error, just test the socket stale, and it is good when you want to reuse a socket. See org/apache/httpcomponents/httpcore/4.4.10/httpcore-4.4.10-sources.jar!/org/apache/http/pool/AbstractConnPool.java

这不是错误,只是测试socket stale,当你想重用一个socket时很好。参见 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

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);
}
}

Set socket timeout to 1 ms, and read input stream, return these results:

将套接字超时设置为 1 毫秒,并读取输入流,返回以下结果:

  1. -1 recreate new connection
  2. ">0" reuse connection
  3. timeout exception, reuse connection
  4. IO exception recreate new connection
  1. -1 重新创建新连接
  2. ">0" 重用连接
  3. 超时异常,重用连接
  4. IO 异常重新创建新连接

To avoid this message, just set proper value for validateAfterInactivity , it's the min value of client socket timeout, keep-alive time(return by ConnectionKeepAliveStrategy), server connection timeout, and the delay time for idleConnectionMonitor. This does not check connection state, if connect is reset, a new connection will be created.

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