Solicitação de cliente HTTP Java com tempo limite definido

91

Gostaria de fazer BIT (testes integrados) para vários servidores na minha nuvem. Preciso que a solicitação falhe em um grande tempo limite.

Como devo fazer isso com java?

Tentar algo como o abaixo não parece funcionar.

public class TestNodeAliveness {
 public static NodeStatus nodeBIT(String elasticIP) throws ClientProtocolException, IOException {
  HttpClient client = new DefaultHttpClient();
  client.getParams().setIntParameter("http.connection.timeout", 1);

  HttpUriRequest request = new HttpGet("http://192.168.20.43");
  HttpResponse response = client.execute(request);

  System.out.println(response.toString());
  return null;
 }


 public static void main(String[] args) throws ClientProtocolException, IOException {
  nodeBIT("");
 }
}

- EDITAR: Esclareça qual biblioteca está sendo usada -

Estou usando httpclient do apache, aqui está a seção relevante do pom.xml

 <dependency>
   <groupId>org.apache.httpcomponents</groupId>
   <artifactId>httpclient</artifactId>
   <version>4.0.1</version>
   <type>jar</type>
 </dependency>
Maxim Veksler
fonte
Que biblioteca você está usando para todas as funcionalidades HTTP?
nojo de
Obrigado pelo comentário. Eu atualizei minha postagem.
Maxim Veksler

Respostas:

119
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

...

    // set the connection timeout value to 30 seconds (30000 milliseconds)
    final HttpParams httpParams = new BasicHttpParams();
    HttpConnectionParams.setConnectionTimeout(httpParams, 30000);
    client = new DefaultHttpClient(httpParams);
preguiça
fonte
1
O que isso faz? Um tempo limite do que ele define? Consulte stackoverflow.com/questions/3000767/…
Maxim Veksler
83
O HttpClient do Apache tem dois tempos limites separados: um tempo limite para quanto tempo esperar para estabelecer uma conexão TCP e um tempo limite separado para quanto tempo esperar por um byte de dados subsequente. HttpConnectionParams.setConnectionTimeout () é o primeiro, HttpConnectionParams.setSoTimeout () é o último.
benvolioT
7
Qual é o tempo limite padrão? É 0 = infinito?
Tobia,
1
http.connection.timeout Inteiro O tempo limite até que uma conexão seja estabelecida. Um valor zero significa que o tempo limite não é usado.
maveroid
26
Para futuros leitores: deve-se observar que as classes mencionadas aqui agora estão obsoletas (em 05/07/2016), embora essa provavelmente tenha sido uma boa resposta quando postada em 2010. Veja esta resposta: stackoverflow.com/a/ 19153314/192801 para algo um pouco mais atual.
FrustratedWithFormsDesigner
125

Se você estiver usando o cliente Http versão 4.3 ou superior, deverá usar este:

RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(30 * 1000).build();
HttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
Trovão
fonte
4
Obrigado! Eu gastei 20 minutos tentando descobrir como me livrar dos comandos obsoletos para fazer isso antes de encontrar sua resposta.
vextorspace
Esqueci SocketTimeout. Além disso, "default" significa que é padrão para tudo o HttpClientque o método HttpClientBuilderfrom create () fornecerá por build()meio? Ou apenas os que passam setDefaultRequestConfig(requestConfig)? Estou fazendo sentido?
ADTC
@ADTC Sua pergunta é um pouco confusa :). A configuração de solicitação padrão será usada para todas as instâncias HttpPost, HttpGet, ... usando 'apenas' esse HttpClient. Se você criou outra instância de HttpClient, esta configuração de solicitação não será usada com esse cliente.
Thunder,
35

HttpParams está obsoleto na nova biblioteca Apache HTTPClient. Usar o código fornecido por Laz leva a avisos de depreciação.

Sugiro usar RequestConfig em sua instância HttpGet ou HttpPost:

final RequestConfig params = RequestConfig.custom().setConnectTimeout(3000).setSocketTimeout(3000).build();
httpPost.setConfig(params);
pmartin8
fonte
"usando o código acima" << O SO não é um fórum e as respostas aumentam / diminuem devido a vários fatores, portanto não sabemos a qual código você está se referindo. Você poderia dizer algo como "usando o código da resposta de xyz"?
ADTC
4
Btw, resposta legal. Mas quando comparado com a resposta de Thunder, qual é a diferença entre configurar o RequestConfigem cada HttpPostem oposição a configurá-lo como padrão no HttpClient?
ADTC
2
Sim, você tem razão, o código acima se refere à "resposta aceita" que não deve mudar com o tempo. Vou atualizar minha resposta de qualquer maneira ..
pmartin8
10

Parece que você está usando a API HttpClient, sobre a qual não sei nada, mas você poderia escrever algo semelhante a isso usando o núcleo do Java.

try {

   HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
   con.setRequestMethod("HEAD");
   con.setConnectTimeout(5000); //set timeout to 5 seconds
   return (con.getResponseCode() == HttpURLConnection.HTTP_OK);

} catch (java.net.SocketTimeoutException e) {
   return false;
} catch (java.io.IOException e) {
   return false;
}
dbyrne
fonte
2
Isso não afetará o tempo limite do cliente HTTP Apache.
preguiça de
9
Nunca alegou que sim;)
dbyrne
5
A noção de tempo limite do HttpURLConnection é insuficiente. Se o servidor começar a responder, mas depois travar, o tempo limite nunca será atingido. O HttpClient do Apache é uma escolha melhor por causa dessa diferença.
benvolioT
7

Achei que definir as configurações de tempo limite HttpConnectionParamse HttpConnectionManagernão resolveu nosso caso. Estamos limitados a usar a org.apache.commons.httpclientversão 3.0.1.

Acabei usando um java.util.concurrent.ExecutorServicepara monitorar a HttpClient.executeMethod()ligação.

Aqui está um pequeno exemplo independente

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;

/**
 * @author Jeff Kirby
 * @since <pre>Jun 17, 2011</pre>
 */
public class Example {

   private static final String SITE = "http://some.website.com/upload";
   private static final int TIME_OUT_SECS = 5;

   // upload a file and return the response as a string
   public String post(File file) throws IOException, InterruptedException {
      final Part[] multiPart = { new FilePart("file", file.getName(), file) };
      final EntityEnclosingMethod post = new PostMethod(SITE);
      post.setRequestEntity(new MultipartRequestEntity(multiPart, post.getParams()));
      final ExecutorService executor = Executors.newSingleThreadExecutor();
      final List<Future<Integer>> futures = executor.invokeAll(Arrays.asList(new KillableHttpClient(post)), TIME_OUT_SECS, TimeUnit.SECONDS);
      executor.shutdown();
      if(futures.get(0).isCancelled()) {
         throw new IOException(SITE + " has timed out. It has taken more than " + TIME_OUT_SECS + " seconds to respond");
      }
      return post.getResponseBodyAsString();
   }

   private static class KillableHttpClient implements Callable<Integer> {

      private final EntityEnclosingMethod post;

      private KillableHttpClient(EntityEnclosingMethod post) {
         this.post = post;
      }

      public Integer call() throws Exception {
         return new HttpClient().executeMethod(post);
      }
   }
}
Kirby
fonte
6

O referido método com o mais alto da Laz está obsoleto da versão 4.3 em diante. Portanto, seria melhor usar o objeto Request Config e, em seguida, construir o cliente HTTP

    private CloseableHttpClient createHttpClient()
        {
        CloseableHttpClient httpClient;
        CommonHelperFunctions helperFunctions = new CommonHelperFunctions();
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(306);
        cm.setDefaultMaxPerRoute(108);
        RequestConfig requestConfig = RequestConfig.custom()
            .setConnectTimeout(15000)
            .setSocketTimeout(15000).build();
        httpClient = HttpClients.custom()
            .setConnectionManager(cm)
            .setDefaultRequestConfig(requestConfig).build();
        return httpClient;
        }

O PoolingHttpClientConnectionManager é o usuário para definir o número máximo padrão de conexões e o número máximo de conexões por rota. Eu o defini como 306 e 108, respectivamente. Os valores padrão não serão suficientes para a maioria dos casos.

Para definir o tempo limite: usei o objeto RequestConfig. Você também pode definir a propriedade Tempo limite de solicitação de conexão para definir o tempo limite de espera de conexão do gerenciador de conexões.

Arun Thundyill Saseendran
fonte
5

Isso já foi mencionado em um comentário de Benvoliot acima. Mas, acho que vale a pena uma postagem de nível superior porque com certeza me deixou coçando a cabeça. Estou postando isso para o caso de ajudar alguém.

Eu escrevi um cliente de teste simples e o CoreConnectionPNames.CONNECTION_TIMEOUTtempo limite funciona perfeitamente nesse caso. A solicitação é cancelada se o servidor não responder.

No entanto, dentro do código do servidor que eu estava tentando testar, o código idêntico nunca atinge o tempo limite.

Alterá-lo para expirar na atividade de conexão do soquete ( CoreConnectionPNames.SO_TIMEOUT) em vez da conexão HTTP ( CoreConnectionPNames.CONNECTION_TIMEOUT) corrigiu o problema para mim.

Além disso, leia os documentos do Apache com atenção: http://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/org/apache/http/params/CoreConnectionPNames.html#CONNECTION_TIMEOUT

Observe a parte que diz

Observe que este parâmetro só pode ser aplicado a conexões vinculadas a um endereço local específico.

Espero que isso salve alguém de todos os arranhões de cabeça pelos quais passei. Isso vai me ensinar a não ler a documentação completamente!

Dan Haynes
fonte
2

Op mais tarde declarou que estava usando o Apache Commons HttpClient 3.0.1

 HttpClient client = new HttpClient();
        client.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
        client.getHttpConnectionManager().getParams().setSoTimeout(5000);
rtaft
fonte
1

HttpConnectionParams.setSoTimeout(params, 10*60*1000);// for 10 mins i have set the timeout

Você também pode definir o tempo limite necessário.

Mohammed Irfan Tirupattur
fonte