如何在Java HTTP客户端中设置套接字超时时间

huangapple go评论73阅读模式
英文:

How to set socket timeout in Java HTTP Client

问题

我们希望将所有的 apache-httpclient-4.x 代码迁移到 java-http-client 代码,以减少依赖。在迁移过程中,我在 Java 11 下遇到了以下问题:

如何在 Java HTTP Client 中设置套接字超时?

apache-httpclient-4.x 中,我们可以像这样设置连接超时和套接字超时:

DefaultHttpClient httpClient = new DefaultHttpClient();
int timeout = 5; // 秒
HttpParams httpParams = httpClient.getParams();
httpParams.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, timeout * 1000);
httpParams.setParameter(CoreConnectionPNames.SO_TIMEOUT, timeout * 1000);

java-http-client 中,我只能像这样设置连接超时:

HttpClient httpClient = HttpClient.newBuilder()
                                  .connectTimeout(Duration.ofSeconds(5))
                                  .build();

但我没有找到设置套接字超时的方法。在将来是否有任何方法或者相关的未解决问题可以支持这个功能?

英文:

We want to migrate all our apache-httpclient-4.x code to java-http-client code to reduce dependencies. While migrating them, I ran into the following issue under Java 11:

How to set the socket timeout in Java HTTP Client?

With apache-httpclient-4.x we can set the connection timeout and the socket timeout like this:

DefaultHttpClient httpClient = new DefaultHttpClient();
int timeout = 5; // seconds
HttpParams httpParams = httpClient.getParams();
httpParams.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, timeout * 1000);
httpParams.setParameter(CoreConnectionPNames.SO_TIMEOUT, timeout * 1000);

With java-http-client I can only set the connection timeout like this:

HttpClient httpClient = HttpClient.newBuilder()
                                  .connectTimeout(Duration.ofSeconds(5))
                                  .build()

But I found no way to set the socket timeout. Is there any way or an open issue to support that in the future?

答案1

得分: 21

你可以在 HttpRequest.Builder 层面通过 timeout 方法进行指定:

HttpClient httpClient = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(5))
                .build();

HttpRequest httpRequest = HttpRequest.newBuilder()
                .uri(URI.create("..."))
                .timeout(Duration.ofSeconds(5)) // 这里
                .build();


httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());

如果成功建立连接但无法在期望的时间内接收到响应,将会抛出 java.net.http.HttpTimeoutException: 请求超时(与 java.net.http.HttpConnectTimeoutException: HTTP连接超时 相对应,后者将在未成功建立连接时抛出)。

英文:

You can specify it at the HttpRequest.Builder level via the timeout method:

HttpClient httpClient = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(5))
                .build();

HttpRequest httpRequest = HttpRequest.newBuilder()
                .uri(URI.create("..."))
                .timeout(Duration.ofSeconds(5)) //this
                .build();


httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());

If you've got connected successfully but not able to receive a response at the desired amount of time, java.net.http.HttpTimeoutException: request timed out will be thrown (in contrast with java.net.http.HttpConnectTimeoutException: HTTP connect timed out which will be thrown if you don't get a successful connection).

答案2

得分: 0

在Java Http Client中似乎没有一种指定数据包流(套接字超时)超时的方法。

我在OpenJDK上找到了一个增强请求,似乎涵盖了这种可能性 - https://bugs.openjdk.org/browse/JDK-8258397

链接内容:

HttpClient允许您设置连接超时(HttpClient.Builder)和请求超时(HttpRequest.Builder)。然而,一旦读取完响应头,请求超时就会被取消。目前没有涵盖接收正文的超时。

调用者的一个可能选择是利用CompletableFuture API(get/join将接受超时,或者可以调用CF::orTimeout)。
根据我记得的情况 - 在这种情况下,调用者仍然有责任取消请求。我们可能希望重新审视并可能更改这一点。
这里的缺点是我们的一些BodyHandlers(ofPublisher,ofInputStream)将立即返回 - 因此在这种情况下,CF API将无法帮助。
这可能是件好事(或者不是)。

另一个可能性是在HttpRequest.Builder上添加一个正文超时。这将覆盖所有情况 - 但是,如果调用者没有足够快地读取正文,我们真的希望在ofInputStream或ofPublisher的情况下超时吗?

英文:

There doesn't seem to be a way to specify a timeout on the flow of packets (socket timeout) on the Java Http Client.

I found an enhancement request on OpenJDK which seems to cover this possibility - https://bugs.openjdk.org/browse/JDK-8258397

Content from the link

The HttpClient lets you set a connection timeout (HttpClient.Builder) and a request timeout (HttpRequest.Builder). However the request timeout will be cancelled as soon as the response headers have been read. There is currently no timeout covering the reception of the body.

A possibility for the caller is to make use of the CompletableFuture API (get/join will accept a timeout, or CF::orTimeout can be called).
IIRC - in that case, it will still be the responsibility of the caller to cancel the request. We might want to reexamine and possibility change that.
The disadvantage here is that some of our BodyHandlers (ofPublisher, ofInputStream) will return immediately - so the CF API won't help in this case.
This might be a good thing (or not).

Another possibility could be to add a body timeout on HttpRequest.Builder. This would then cover all cases - but do we really want to timeout in the case of ofInputStream or ofPublisher if the caller doesn't read the body fast enough?

huangapple
  • 本文由 发表于 2020年10月27日 15:52:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/64550136.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定