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.