使用 TLS 时,Apache HttpClient 5 会阻塞 requestTimeout 设置的持续时间的两倍

问题描述 投票:0回答:1

我的应用程序在使用 Spring 的 RestTemplate(配置 Apache HttpClient 5 作为底层 http)时遇到问题 客户。我的应用程序正在调用下游遗留系统,虽然该系统“关闭”以进行维护,但它仍然接受连接(TLS 握手等),但从不返回响应。

我遇到的问题是,当我在 Apache 客户端上将请求超时设置为 8 秒时,发送到此下游服务的请求将被阻塞两倍的超时设置(16 秒)。

我已将其与 Apache HttpClient 隔离,并使用自签名证书在单元测试中重现了此行为。由于重现所需的代码太长,无法在此处发布,因此我有一个存储库,其中的测试在此处重现问题:apache-httpclient-socket-timeout-test

您可以在以下日志中看到,在配置的 8 秒后确实发生了读取超时,但它又阻塞了 8 秒以关闭连接。使用 HTTP 不会发生这种情况,只有 HTTPS 才会发生这种情况。

14:45:21.587 [main] DEBUG org.apache.hc.client5.http.wire -- http-outgoing-1 >> "[\r][\n]"
14:45:29.589 [main] DEBUG org.apache.hc.client5.http.wire -- http-outgoing-1 << "[read] I/O error: Read timed out"
14:45:29.589 [main] DEBUG o.a.h.c.h.i.i.DefaultManagedHttpClientConnection -- http-outgoing-1 Close connection
14:45:37.591 [main] DEBUG o.a.h.c.h.i.c.InternalHttpClient -- InternalConnectionEndpoint-7eb6b6b6 endpoint closed

在我将此作为错误提交给 Apache 之前,我在这里发帖看看是否有其他人遇到过这个问题 - 也许我的配置中有问题?

为了减少这是服务器问题的变量,我添加了一个使用纯 http 发送请求的测试,以及一个使用 JDK HttpClient 发送 TLS 请求的测试,并且两者都遵循我设置的 requestTimeout 。但是,我将此测试连接到非 java(node-js 模拟应用程序),并且无法重现...

所以也许,这是一个 java 套接字问题 - 但是,我已经在几个 JVM 实现中对此进行了测试,并得到了相同的结果。

java https
1个回答
0
投票

我在 apache http 客户端版本 5.3.1 中也遇到了这个问题。 我使用 -Djavax.net.debug=all

启用了 ssl 调试日志

我可以看到它再次尝试关闭连接和超时:)

12:32:06,747 DEBUG [qtp1341085586-38] DefaultManagedHttpClientConnection - local http-outgoing-1 Close connection
javax.net.ssl|WARNING|62|qtp1341085586-38|2025-01-02 12:32:08.761 CET|SSLSocketImpl.java:1214|input stream close depletion failed (
"throwable" : {
  java.net.SocketTimeoutException: Read timed out
    at java.base/sun.nio.ch.NioSocketImpl.timedRead(NioSocketImpl.java:283)
    at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:309)
    at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350)
    at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803)
    at java.base/java.net.Socket$SocketInputStream.read(Socket.java:966)
    at java.base/java.net.Socket$SocketInputStream.read(Socket.java:961)
    at java.base/sun.security.ssl.SSLSocketInputRecord.deplete(SSLSocketInputRecord.java:498)
    at java.base/sun.security.ssl.SSLSocketImpl$AppInputStream.readLockedDeplete(SSLSocketImpl.java:1210)
    at java.base/sun.security.ssl.SSLSocketImpl$AppInputStream.deplete(SSLSocketImpl.java:1184)
    at java.base/sun.security.ssl.SSLSocketImpl.bruteForceCloseInput(SSLSocketImpl.java:802)
    at java.base/sun.security.ssl.SSLSocketImpl.duplexCloseOutput(SSLSocketImpl.java:655)
    at java.base/sun.security.ssl.SSLSocketImpl.close(SSLSocketImpl.java:579)
    at org.apache.hc.core5.http.impl.io.BHttpConnectionBase.close(BHttpConnectionBase.java:256)
    at org.apache.hc.core5.http.impl.io.DefaultBHttpClientConnection.close(DefaultBHttpClientConnection.java:68)
    at org.apache.hc.client5.http.impl.io.DefaultManagedHttpClientConnection.close(DefaultManagedHttpClientConnection.java:158)
    at org.apache.hc.core5.io.Closer.close(Closer.java:48)
    at org.apache.hc.core5.io.Closer.closeQuietly(Closer.java:71)

显然这里使用了相同的超时设置。

有人知道这个问题的解决方案吗?

© www.soinside.com 2019 - 2024. All rights reserved.