Apache HttpClient Timeout – Apache HttpClient超时

最后修改: 2013年 7月 25日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

This tutorial will show how to configure a timeout with the Apache HttpClient 4.

本教程将展示如何用Apache HttpClient 4配置一个超时。

If you want to dig deeper and learn other cool things you can do with the HttpClient – head on over to the main HttpClient tutorial.

如果你想更深入地了解你可以用HttpClient做的其他很酷的事情–请到主要HttpClient 教程

2. Configuring Timeouts Before HttpClient 4.3

2.HttpClient4.3之前配置超时

2.1. Raw String Parameters

2.1.原始字符串参数

Before version 4.3 came out, the HttpClient came with a lot of configuration parameters, and all of these could be set in a generic, map-like manner.

在4.3版本出来之前,HttpClient带有很多配置参数,而且所有这些都可以用一种通用的、类似地图的方式来设置。

There were 3 timeout parameters to configure:

3个超时参数需要配置

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);
httpParams.setParameter(
  ClientPNames.CONN_MANAGER_TIMEOUT, new Long(timeout * 1000));

2.2. API

2.2.API

The more important of these parameters – namely the first two – could also be set via a more type-safe API:

这些参数中更重要的参数–即前两个–也可以通过一个更安全的类型的API来设置。

DefaultHttpClient httpClient = new DefaultHttpClient();

int timeout = 5; // seconds
HttpParams httpParams = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(
  httpParams, timeout * 1000); // http.connection.timeout
HttpConnectionParams.setSoTimeout(
  httpParams, timeout * 1000); // http.socket.timeout

The third parameter doesn’t have a custom setter in HttpConnectionParams, and it’ll still need to be set manually via the setParameter method.

第三个参数在HttpConnectionParams中没有自定义设置器,它仍然需要通过setParameter方法手动设置。

3. Configure Timeouts Using the New 4.3. Builder

3.使用新的4.3.Builder配置超时。建设者

The fluent, builder API introduced in 4.3 provides the right way to set timeouts at a high level:

4.3中引入的流畅的构建器API提供了在高水平上设置超时的正确方法

int timeout = 5;
RequestConfig config = RequestConfig.custom()
  .setConnectTimeout(timeout * 1000)
  .setConnectionRequestTimeout(timeout * 1000)
  .setSocketTimeout(timeout * 1000).build();
CloseableHttpClient client = 
  HttpClientBuilder.create().setDefaultRequestConfig(config).build();

That is the recommended way of configuring all three timeouts in a type-safe and readable manner.

这是以类型安全和可读的方式配置所有三种超时的推荐方式。

4. Timeout Properties Explained

4.超时属性解释

Now, let’s explain what these various types of timeouts mean:

现在,让我们解释一下这些不同类型的超时意味着什么。

  • the Connection Timeout (http.connection.timeout) – the time to establish the connection with the remote host
  • the Socket Timeout (http.socket.timeout) – the time waiting for data – after establishing the connection; maximum time of inactivity between two data packets
  • the Connection Manager Timeout (http.connection-manager.timeout) – the time to wait for a connection from the connection manager/pool

The first two parameters – the connection and socket timeouts – are the most important. However, setting a timeout for obtaining a connection is definitely important in high load scenarios, which is why the third parameter shouldn’t be ignored.

前两个参数–连接和套接字超时–是最重要的。然而,在高负载情况下,设置获得连接的超时肯定是重要的,这就是为什么第三个参数不应该被忽视。

5. Using the HttpClient

5.使用HttpClient

After configuring it, we can now use the client to perform HTTP requests:

配置好之后,我们现在可以使用客户端来执行HTTP请求。

HttpGet getMethod = new HttpGet("http://host:8080/path");
HttpResponse response = httpClient.execute(getMethod);
System.out.println(
  "HTTP Status of response: " + response.getStatusLine().getStatusCode());

With the previously defined client, the connection to the host will time out in 5 seconds. Also, if the connection is established but no data is received, the timeout will also be 5 additional seconds.

使用先前定义的客户端,与主机的连接将在5秒内超时。另外,如果连接已经建立,但没有收到数据,超时也将是额外的5秒

Note that the connection timeout will result in an org.apache.http.conn.ConnectTimeoutException being thrown, while socket timeout will result in a java.net.SocketTimeoutException.

注意,连接超时将导致抛出org.apache.http.conn.ConnectTimeoutException,而套接字超时将导致java.net.SocketTimeoutException

6. Hard Timeout

6.硬性超时

While setting timeouts on establishing the HTTP connection and not receiving data is very useful, sometimes we need to set a hard timeout for the entire request.

虽然在建立HTTP连接和不接收数据时设置超时是非常有用的,但有时我们需要为整个请求设置一个硬超时

For example, the download of a potentially large file fits into this category. In this case, the connection may be successfully established, data may be consistently coming through, but we still need to ensure that the operation doesn’t go over some specific time threshold.

例如,下载一个潜在的大文件就属于这个类别。在这种情况下,连接可能已经成功建立,数据可能持续不断地传过来,但我们仍然需要确保操作不超过某些特定的时间阈值。

HttpClient doesn’t have any configuration that allows us to set an overall timeout for a request; it does, however, provide abort functionality for requests, so we can leverage that mechanism to implement a simple timeout mechanism:

HttpClient没有任何配置允许我们为一个请求设置总体超时;但是,它确实为请求提供了中止功能,所以我们可以利用这一机制来实现一个简单的超时机制。

HttpGet getMethod = new HttpGet(
  "http://localhost:8080/httpclient-simple/api/bars/1");

int hardTimeout = 5; // seconds
TimerTask task = new TimerTask() {
    @Override
    public void run() {
        if (getMethod != null) {
            getMethod.abort();
        }
    }
};
new Timer(true).schedule(task, hardTimeout * 1000);

HttpResponse response = httpClient.execute(getMethod);
System.out.println(
  "HTTP Status of response: " + response.getStatusLine().getStatusCode());

We’re making use of the java.util.Timer and java.util.TimerTask to set up a simple delayed task which aborts the HTTP GET request after a 5 seconds hard timeout.

我们利用java.util.Timerjava.util.TimerTask来设置一个简单的延迟任务,在硬超时5秒后中止HTTP GET请求

7. Timeout and DNS Round Robin – Something to Be Aware Of

7.超时和DNS轮询–需要注意的问题

It’s quite common that some larger domains will be using a DNS round robin configuration – essentially having the same domain mapped to multiple IP addresses. This introduces a new challenge for a timeout against such a domain, simply because of the way HttpClient will try to connect to that domain that times out:

很常见的是,一些较大的域会使用DNS轮流配置–基本上是将同一个域映射到多个IP地址上。这为针对这样一个域名的超时带来了新的挑战,仅仅是因为HttpClient将尝试连接到那个超时的域名的方式。

  • HttpClient gets the list of IP routes to that domain
  • it tries the first one – that times out (with the timeouts we configure)
  • it tries the second one – that also times out
  • and so on …

So, as you can see – the overall operation will not time out when we expect it to. Instead – it will time out when all the possible routes have timed out. What’s more – this will happen completely transparently for the client (unless you have your log configured at the DEBUG level).

因此,正如你所看到的–整个操作不会在我们期望的时候超时。相反,它将在所有可能的路线都超时的时候超时。更重要的是,这对客户端来说是完全透明的(除非你的日志被配置为DEBUG级别)。

Here’s a simple example you can run and replicate this issue:

这里有一个简单的例子,你可以运行并复制这个问题。

int timeout = 3;
RequestConfig config = RequestConfig.custom().
  setConnectTimeout(timeout * 1000).
  setConnectionRequestTimeout(timeout * 1000).
  setSocketTimeout(timeout * 1000).build();
CloseableHttpClient client = HttpClientBuilder.create()
  .setDefaultRequestConfig(config).build();

HttpGet request = new HttpGet("http://www.google.com:81");
response = client.execute(request);

You will notice the retrying logic with a DEBUG log level:

你会注意到重试逻辑有一个DEBUG日志级别。

DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connecting to www.google.com/173.194.34.212:81
DEBUG o.a.h.i.c.HttpClientConnectionOperator - 
 Connect to www.google.com/173.194.34.212:81 timed out. Connection will be retried using another IP address

DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connecting to www.google.com/173.194.34.208:81
DEBUG o.a.h.i.c.HttpClientConnectionOperator - 
 Connect to www.google.com/173.194.34.208:81 timed out. Connection will be retried using another IP address

DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connecting to www.google.com/173.194.34.209:81
DEBUG o.a.h.i.c.HttpClientConnectionOperator - 
 Connect to www.google.com/173.194.34.209:81 timed out. Connection will be retried using another IP address
//...

8. Conclusion

8.结论

This tutorial discussed how to configure the various types of timeouts available for an HttpClient. It also illustrated a simple mechanism for hard timeout of an ongoing HTTP connection.

本教程讨论了如何为HttpClient配置各种可用的超时类型。它还说明了一个简单的机制,用于正在进行的HTTP连接的硬超时。

The implementation of these examples can be found in the GitHub project.

这些例子的实现可以在GitHub 项目中找到。