Richiesta client HTTP Java con timeout definito


92

Vorrei fare BIT (Built in test) su un numero di server nel mio cloud. Ho bisogno che la richiesta non riesca in caso di timeout di grandi dimensioni.

Come dovrei farlo con java?

Provare qualcosa come il seguente non sembra funzionare.

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

- MODIFICA: chiarisci quale libreria viene utilizzata -

Sto usando httpclient da apache, ecco la sezione pom.xml pertinente

 <dependency>
   <groupId>org.apache.httpcomponents</groupId>
   <artifactId>httpclient</artifactId>
   <version>4.0.1</version>
   <type>jar</type>
 </dependency>

Quale libreria stai usando per tutte le funzionalità HTTP?
nojo

Grazie per il commento. Ho aggiornato il mio post.
Maxim Veksler

Risposte:


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

1
Cosa fa questo? Un timeout di ciò che imposta? Si prega di consultare stackoverflow.com/questions/3000767/...
Maxim Veksler

84
HttpClient di Apache ha due timeout separati: un timeout per il tempo di attesa per stabilire una connessione TCP e un timeout separato per il tempo di attesa per un successivo byte di dati. HttpConnectionParams.setConnectionTimeout () è il primo, HttpConnectionParams.setSoTimeout () è il secondo.
benvolioT

7
Qual è il timeout predefinito? È 0 = infinito?
Tobia

1
http.connection.timeout Intero Il timeout fino a quando non viene stabilita una connessione. Un valore pari a zero significa che il timeout non viene utilizzato.
maveroid

26
Per i lettori futuri: Va notato che le classi a cui si fa riferimento qui sono ora deprecate (a partire dal 05/07/2016), anche se questa era probabilmente una buona risposta quando è stata pubblicata nel 2010. Vedi questa risposta: stackoverflow.com/a/ 19153314/192801 per qualcosa di un po 'più attuale.
FrustratedWithFormsDesigner

125

Se stai usando Http Client versione 4.3 e successive dovresti usare questo:

RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(30 * 1000).build();
HttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();

4
Grazie! Ho passato almeno 20 minuti a cercare di capire come sbarazzarmi dei comandi deprecati per farlo prima di trovare la tua risposta.
vextorspace

Dimenticato SocketTimeout. Inoltre, "default" significa che è predefinito per tutto HttpClientciò che il HttpClientBuilderfrom create () darà tramite il build()metodo? O solo quelli che passano setDefaultRequestConfig(requestConfig)? Ho senso?
ADTC

@ADTC La tua domanda è un po 'confusa :). La configurazione della richiesta predefinita verrà utilizzata per tutte le istanze HttpPost, HttpGet, ... utilizzando "solo" quel HttpClient. Se hai creato un'altra istanza HttpClient, questa configurazione della richiesta non verrà utilizzata con quel client.
Thunder

35

HttpParams è deprecato nella nuova libreria HTTPClient di Apache. L'utilizzo del codice fornito da Laz porta ad avvisi di deprecazione.

Suggerisco di utilizzare RequestConfig invece sulla tua istanza HttpGet o HttpPost:

final RequestConfig params = RequestConfig.custom().setConnectTimeout(3000).setSocketTimeout(3000).build();
httpPost.setConfig(params);

"utilizzando il codice sopra" << SO non è un forum e le risposte si muovono su / giù a causa di diversi fattori, quindi non sappiamo a quale codice ti riferisci. Potresti dire qualcosa come "usare il codice dalla risposta di xyz"?
ADTC

4
A proposito, risposta chiara. Ma rispetto alla risposta di Thunder, qual è la differenza tra l'impostazione di RequestConfigin ogni HttpPoste l'impostazione predefinita in HttpClient?
ADTC

2
Sì, hai ragione, il codice sopra si riferisce alla "risposta accettata" che non dovrebbe cambiare nel tempo. Aggiornerò comunque la mia risposta ..
pmartin8

10

Sembra che tu stia usando l'API HttpClient, di cui non so nulla, ma potresti scrivere qualcosa di simile a questo usando Java core.

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

2
Ciò non influirà sul timeout per il client HTTP Apache.
laz

9
Non lo ha mai affermato;)
dbyrne,

5
La nozione di timeout di HttpURLConnection è insufficiente. Se il server inizia a rispondere, ma poi si blocca, il timeout non viene mai raggiunto. HttpClient di Apache è una scelta migliore a causa di questa differenza.
benvolioT

7

Ho scoperto che l'impostazione delle impostazioni di timeout HttpConnectionParamse HttpConnectionManagernon ha risolto il nostro caso. Siamo limitati all'utilizzo della org.apache.commons.httpclientversione 3.0.1.

Ho finito per usare un java.util.concurrent.ExecutorServiceper monitorare la HttpClient.executeMethod()chiamata.

Ecco un piccolo esempio autonomo

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

7

Il suddetto metodo con i più alti di Laz è deprecato dalla versione 4.3 in poi. Quindi sarebbe meglio utilizzare l'oggetto Request Config e quindi creare il client 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;
        }

PoolingHttpClientConnectionManager è l'utente per impostare il numero massimo predefinito di connessioni e il numero massimo di connessioni per route. L'ho impostato rispettivamente come 306 e 108. I valori predefiniti non saranno sufficienti per la maggior parte dei casi.

Per l'impostazione del timeout: ho utilizzato l'oggetto RequestConfig. È inoltre possibile impostare la proprietà Timeout richiesta di connessione per impostare il timeout per l'attesa della connessione da Connection manager.


5

Questo è già stato menzionato in un commento di benvoliot sopra. Ma penso che valga la pena un post di alto livello perché sicuramente mi ha fatto grattare la testa. Sto postando questo nel caso in cui aiuti qualcun altro.

Ho scritto un semplice client di prova e il CoreConnectionPNames.CONNECTION_TIMEOUTtimeout funziona perfettamente in quel caso. La richiesta viene annullata se il server non risponde.

All'interno del codice del server che stavo effettivamente cercando di testare, tuttavia, il codice identico non scade mai.

Cambiarlo in timeout sull'attività di connessione socket ( CoreConnectionPNames.SO_TIMEOUT) piuttosto che sulla connessione HTTP ( CoreConnectionPNames.CONNECTION_TIMEOUT) ha risolto il problema per me.

Inoltre, leggi attentamente i documenti di Apache: http://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/org/apache/http/params/CoreConnectionPNames.html#CONNECTION_TIMEOUT

Nota la parte che dice

Si noti che questo parametro può essere applicato solo alle connessioni associate a un particolare indirizzo locale.

Spero che questo salvi a qualcun altro tutti i graffi alla testa che ho subito. Questo mi insegnerà a non leggere completamente la documentazione!


2

Op successivamente ha dichiarato che stavano usando Apache Commons HttpClient 3.0.1

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

1

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

Puoi anche definire il timeout richiesto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.