Tempo limite do HttpClient

Tempo limite do HttpClient

1. Visão geral

Este tutorial mostrará comoconfigure a timeout with the Apache HttpClient 4.

Se você quiser se aprofundar e aprender outras coisas legais que você pode fazer com o HttpClient - vá parathe main HttpClient tutorial.

Leitura adicional:

Gerenciamento de conexões HttpClient

Como abrir, gerenciar e fechar conexões com o Apache HttpClient 4.

Read more →

HttpClient 4 - Seguir redirecionamentos para o POST

Como ativar o redirecionamento do POST com o Apache HttpClient.

Read more →

Configuração avançada do HttpClient

Configurações HttpClient para casos de uso avançados.

Read more →

2. Configure os tempos limite por meio dos parâmetros deString brutos

OHttpClient vem com vários parâmetros de configuração e todos eles podem ser definidos de uma maneira genérica, semelhante a um mapa.

Existem3 timeout parameters to configure:

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

3. Configure tempos limite por meio da API

O mais importante desses parâmetros - os dois primeiros - também pode ser definido por meio de uma API mais segura para o tipo:

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

O terceiro parâmetro não tem um configurador personalizado emHttpConnectionParams, e ainda precisará ser definido manualmente por meio do métodosetParameter.

4. Configurar tempos limite usando o novo 4.3. Construtor

A API fluente do builder introduzida em 4.3 fornecethe right way to set timeouts at a high level:

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

Essa é a maneira recomendada de configurar os três tempos limite de maneira segura e legível.

5. Propriedades de tempo limite explicadas

Agora, vamos explicar o que esses vários tipos de tempo limite significam:

  • oConnection Timeout (http.connection.timeout) - o tempo para estabelecer a conexão com o host remoto

  • oSocket Timeout (http.socket.timeout) - o tempo de espera pelos dados - após estabelecer a conexão; tempo máximo de inatividade entre dois pacotes de dados

  • oConnection Manager Timeout (http.connection-manager.timeout) - o tempo de espera por uma conexão do gerenciador de conexões / pool

Os dois primeiros parâmetros - os tempos limite de conexão e soquete - são os mais importantes. No entanto, definir um tempo limite para obter uma conexão é definitivamente importante em cenários de alta carga, razão pela qual o terceiro parâmetro não deve ser ignorado.

6. Usando oHttpClient

Depois de configurá-lo, agora podemos usar o cliente para executar solicitações HTTP:

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

Com o cliente definido anteriormente,the connection to the host will time out in 5 seconds. Além disso, se a conexão for estabelecida, mas nenhum dado for recebido, o tempo limite também será5 additional seconds.

Observe que o tempo limite da conexão resultará emorg.apache.http.conn.ConnectTimeoutException sendo lançado, enquanto o tempo limite do soquete resultará emjava.net.SocketTimeoutException.

7. Hard Timeout

Embora seja muito útil definir tempos limite ao estabelecer a conexão HTTP e não receber dados, às vezes precisamos definir umhard timeout for the entire request.

Por exemplo, o download de um arquivo potencialmente grande se encaixa nessa categoria. Nesse caso, a conexão pode ser estabelecida com sucesso, os dados podem estar chegando de forma consistente, mas ainda precisamos garantir que a operação não ultrapasse algum limite de tempo específico.

HttpClient não tem nenhuma configuração que nos permita definir um tempo limite geral para uma solicitação; ele fornece, entretanto,abort functionality for requests, para que possamos aproveitar esse mecanismo para implementar um mecanismo de tempo limite simples:

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

Estamos usandojava.util.Timerejava.util.TimerTask para configurarsimple delayed task which aborts the HTTP GET request após um tempo limite difícil de 5 segundos.

8. Tempo limite e rodízio de DNS - algo a ter em atenção

É bastante comum que alguns domínios maiores usem uma configuração de rodízio DNS - essencialmente tendothe same domain mapped to multiple IP addresses. Isso apresenta um novo desafio para um tempo limite contra esse domínio, simplesmente devido à maneira como o HttpClient tentará se conectar ao domínio que atinge o tempo limite:

  • HttpClient obtémthe list of IP routes para esse domínio

  • ele tentathe first one - que atinge o tempo limite (com os tempos limite que configuramos)

  • ele tentathe second one - que também atinge o tempo limite

  • e assim por diante …

Então, como você pode ver -the overall operation will not time out when we expect it to. Em vez disso, o tempo limite será excedido quando todas as rotas possíveis expirarem. Além do mais - isso acontecerá de forma totalmente transparente para o cliente (a menos que você tenha seu log configurado no nível DEBUG).

Aqui está um exemplo simples que você pode executar e replicar esse problema:

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

Você observará a lógica de nova tentativa com um nível de log 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
//...

9. Conclusão

Este tutorial discutiu como configurar os vários tipos de tempo limite disponíveis para umHttpClient. Também ilustrou um mecanismo simples para esgotar o tempo limite de uma conexão HTTP em andamento.

A implementação desses exemplos pode ser encontrada emthe GitHub project.