Solicitud de cliente HTTP de Java con tiempo de espera definido

92

Me gustaría hacer BIT (pruebas integradas) en varios servidores de mi nube. Necesito que la solicitud falle en un tiempo de espera grande.

¿Cómo debo hacer esto con Java?

Probar algo como el siguiente no 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: aclare qué biblioteca se está utilizando -

Estoy usando httpclient de apache, aquí está la sección pom.xml relevante

 <dependency>
   <groupId>org.apache.httpcomponents</groupId>
   <artifactId>httpclient</artifactId>
   <version>4.0.1</version>
   <type>jar</type>
 </dependency>
Maxim Veksler
fuente
¿Qué biblioteca está utilizando para toda la funcionalidad HTTP?
Nojo
Gracias por el comentario. Actualicé mi publicación.
Maxim Veksler

Respuestas:

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);
laz
fuente
1
¿Qué hace esto? ¿Un tiempo de espera de lo que establece? Consulte stackoverflow.com/questions/3000767/…
Maxim Veksler
84
HttpClient de Apache tiene dos tiempos de espera separados: un tiempo de espera para el tiempo de espera para establecer una conexión TCP y un tiempo de espera separado para el tiempo de espera para un byte de datos posterior. HttpConnectionParams.setConnectionTimeout () es el primero, HttpConnectionParams.setSoTimeout () es el último.
benvolioT
7
¿Cuál es el tiempo de espera predeterminado? ¿Es 0 = infinito?
Tobia
1
http.connection.timeout Entero El tiempo de espera hasta que se establezca una conexión. Un valor de cero significa que no se usa el tiempo de espera.
maveroid
26
Para futuros lectores: Cabe señalar que las clases a las que se hace referencia aquí ahora están obsoletas (a partir del 05/07/2016), aunque probablemente esta fue una buena respuesta cuando se publicó en 2010. Vea esta respuesta: stackoverflow.com/a/ 19153314/192801 por algo un poco más actual.
FrustratedWithFormsDesigner
125

Si está utilizando Http Client versión 4.3 y superior, debería utilizar esto:

RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(30 * 1000).build();
HttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
Trueno
fuente
4
¡Gracias! Pasé al menos 20 minutos tratando de averiguar cómo deshacerme de los comandos obsoletos para hacer esto antes de encontrar su respuesta.
vextorspace
Olvidé SocketTimeout. Además, ¿"predeterminado" significa que es predeterminado para todo lo HttpClientque HttpClientBuilderfrom create () dará a través del build()método? ¿O solo los que pasan setDefaultRequestConfig(requestConfig)? ¿Tengo sentido?
ADTC
@ADTC Tu pregunta es un poco confusa :). La configuración de solicitud predeterminada se usará para todas las instancias de HttpPost, HttpGet, ... usando 'solo' ese HttpClient. Si creó otra instancia de HttpClient, esta configuración de solicitud no se utilizará con ese cliente.
Thunder
35

HttpParams está en desuso en la nueva biblioteca Apache HTTPClient. El uso del código proporcionado por Laz genera advertencias de obsolescencia.

Sugiero usar RequestConfig en su lugar en su instancia de HttpGet o HttpPost:

final RequestConfig params = RequestConfig.custom().setConnectTimeout(3000).setSocketTimeout(3000).build();
httpPost.setConfig(params);
pmartin8
fuente
"usando el código anterior" << SO no es un foro y las respuestas se mueven hacia arriba o hacia abajo debido a varios factores, por lo que no sabemos a qué código se está refiriendo. ¿Podría decir algo como "usando el código de la respuesta de xyz"?
ADTC
4
Por cierto, buena respuesta. Pero en comparación con la respuesta de Thunder, ¿cuál es la diferencia entre configurar el RequestConfigen cada HttpPosten lugar de configurarlo como predeterminado en el HttpClient?
ADTC
2
Sí, tienes razón, el código anterior se refiere a la "respuesta aceptada" que no debería cambiar a tiempo. Actualizaré mi respuesta de todos modos ..
pmartin8
10

Parece que está utilizando la API de HttpClient, de la que no sé nada, pero podría escribir algo similar a esto utilizando el núcleo de 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
fuente
2
Esto no afectará el tiempo de espera para Apache HTTP Client.
laz
9
Nunca afirmó que lo hiciera;)
dbyrne
5
La noción de tiempo de espera de HttpURLConnection es insuficiente. Si el servidor comienza a responder, pero luego se cuelga, nunca se alcanza el tiempo de espera. HttpClient de Apache es una mejor opción debido a esta diferencia.
benvolioT
7

Descubrí que establecer la configuración del tiempo de espera HttpConnectionParamsy HttpConnectionManagerno resolvió nuestro caso. Estamos limitados a usar la org.apache.commons.httpclientversión 3.0.1.

Terminé usando un java.util.concurrent.ExecutorServicepara monitorear la HttpClient.executeMethod()llamada.

Aquí hay un pequeño ejemplo autónomo

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
fuente
7

Dicho método con los más altos de Laz está obsoleto a partir de la versión 4.3. Por lo tanto, sería mejor utilizar el objeto de configuración de solicitud y luego construir el 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;
        }

El PoolingHttpClientConnectionManager es el usuario para establecer el número máximo predeterminado de conexiones y el número máximo de conexiones por ruta. Lo he configurado como 306 y 108 respectivamente. Los valores predeterminados no serán suficientes para la mayoría de los casos.

Para configurar el tiempo de espera: he utilizado el objeto RequestConfig. También puede establecer la propiedad Tiempo de espera de solicitud de conexión para configurar el tiempo de espera para esperar la conexión desde el Administrador de conexiones.

Arun Thundyill Saseendran
fuente
5

Esto ya fue mencionado en un comentario de benvoliot. anterior. Pero, creo que vale la pena una publicación de alto nivel porque seguro que me hizo rascar la cabeza. Estoy publicando esto en caso de que ayude a alguien más.

Escribí un cliente de prueba simple y el CoreConnectionPNames.CONNECTION_TIMEOUTtiempo de espera funciona perfectamente en ese caso. La solicitud se cancela si el servidor no responde.

Sin embargo, dentro del código del servidor que estaba tratando de probar, el código idéntico nunca se agota.

Cambiarlo para que se agote el tiempo de espera en la actividad de conexión del socket ( CoreConnectionPNames.SO_TIMEOUT) en lugar de la conexión HTTP ( CoreConnectionPNames.CONNECTION_TIMEOUT) solucionó el problema.

Además, lea los documentos de Apache detenidamente: http://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/org/apache/http/params/CoreConnectionPNames.html#CONNECTION_TIMEOUT

Note la parte que dice

Tenga en cuenta que este parámetro solo se puede aplicar a conexiones que están vinculadas a una dirección local en particular.

Espero que eso le ahorre a alguien más todo el rascado de cabeza por el que pasé. ¡Eso me enseñará a no leer la documentación a fondo!

Dan Haynes
fuente
2

Op luego declaró que estaban usando Apache Commons HttpClient 3.0.1

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

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

También puede definir su tiempo de espera requerido.

Mohammed Irfan Tirupattur
fuente