Java HTTP Client Request mit definiertem Timeout

89

Ich möchte BIT (Built in Tests) für eine Reihe von Servern in meiner Cloud erstellen. Ich brauche die Anfrage, um bei großer Zeitüberschreitung fehlzuschlagen.

Wie soll ich das mit Java machen?

Es scheint nicht zu funktionieren, so etwas wie das Folgende zu versuchen.

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

- BEARBEITEN: Klären Sie, welche Bibliothek verwendet wird -

Ich verwende httpclient von Apache. Hier ist der entsprechende Abschnitt pom.xml

 <dependency>
   <groupId>org.apache.httpcomponents</groupId>
   <artifactId>httpclient</artifactId>
   <version>4.0.1</version>
   <type>jar</type>
 </dependency>
Maxim Veksler
quelle
Welche Bibliothek verwenden Sie für alle HTTP-Funktionen?
Nojo
Danke für den Kommentar. Ich habe meinen Beitrag aktualisiert.
Maxim Veksler

Antworten:

118
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
quelle
1
Was macht das? Eine Zeitüberschreitung von was setzt es? Bitte sehen Sie stackoverflow.com/questions/3000767/…
Maxim Veksler
82
Der HttpClient von Apache verfügt über zwei separate Zeitüberschreitungen: eine Zeitüberschreitung für das Warten auf den Aufbau einer TCP-Verbindung und ein separates Zeitlimit für das Warten auf ein nachfolgendes Datenbyte. HttpConnectionParams.setConnectionTimeout () ist das erstere, HttpConnectionParams.setSoTimeout () ist das letztere.
BenvolioT
6
Was ist das Standardzeitlimit? Ist es 0 = unendlich?
Tobia
1
http.connection.timeout Integer Das Zeitlimit, bis eine Verbindung hergestellt wird. Ein Wert von Null bedeutet, dass das Timeout nicht verwendet wird.
Maveroid
26
An zukünftige Leser: Es sollte beachtet werden, dass die hier genannten Klassen jetzt veraltet sind (Stand: 05.07.2016), obwohl dies wahrscheinlich eine gute Antwort war, als es 2010 veröffentlicht wurde. Siehe diese Antwort: stackoverflow.com/a/ 19153314/192801 für etwas aktuelleres.
FrustratedWithFormsDesigner
124

Wenn Sie Http Client Version 4.3 und höher verwenden, sollten Sie Folgendes verwenden:

RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(30 * 1000).build();
HttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
Donner
quelle
4
Vielen Dank! Ich habe mindestens 20 Minuten damit verbracht, herauszufinden, wie ich die veralteten Befehle loswerden kann, bevor ich Ihre Antwort gefunden habe.
vextorspace
Vergessen SocketTimeout. Bedeutet "Standard" auch, dass es Standard für alles ist HttpClient, was die Methode " HttpClientBuilderfrom create ()" durchgibt build()? Oder nur diejenigen, die durchgehen setDefaultRequestConfig(requestConfig)? Mache ich Sinn?
ADTC
@ADTC Deine Frage ist etwas verwirrend :). Die Standardanforderungskonfiguration wird für alle HttpPost-, HttpGet-, ... -Instanzen verwendet, die 'nur' diesen HttpClient verwenden. Wenn Sie eine andere HttpClient-Instanz erstellt haben, wird diese Anforderungskonfiguration nicht mit diesem Client verwendet.
Donner
35

HttpParams ist in der neuen Apache HTTPClient-Bibliothek veraltet. Die Verwendung des von Laz bereitgestellten Codes führt zu Verfallswarnungen.

Ich schlage vor, RequestConfig stattdessen für Ihre HttpGet- oder HttpPost-Instanz zu verwenden:

final RequestConfig params = RequestConfig.custom().setConnectTimeout(3000).setSocketTimeout(3000).build();
httpPost.setConfig(params);
pmartin8
quelle
"Verwenden des obigen Codes" << SO ist kein Forum und die Antworten werden aufgrund verschiedener Faktoren nach oben / unten verschoben, sodass wir nicht wissen, auf welchen Code Sie sich beziehen. Könnten Sie so etwas wie "Verwenden des Codes aus der Antwort von xyz" sagen?
ADTC
4
Übrigens, ordentliche Antwort. Aber was ist im Vergleich zu Thunders Antwort der Unterschied zwischen dem Setzen des In RequestConfigin Every HttpPostund dem Setzen als Standard in das HttpClient?
ADTC
2
Ja, Sie haben Recht, der obige Code bezieht sich auf die "akzeptierte Antwort", die sich nicht rechtzeitig ändern sollte. Ich werde meine Antwort trotzdem aktualisieren ..
pmartin8
10

Es sieht so aus, als würden Sie die HttpClient-API verwenden, von der ich nichts weiß, aber Sie könnten mit Java-Kern etwas Ähnliches schreiben.

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
quelle
2
Dies hat keine Auswirkungen auf das Zeitlimit für den Apache HTTP-Client.
Laz
9
Ich habe es nie behauptet;)
dbyrne
5
Der Timeout-Begriff von HttpURLConnection ist unzureichend. Wenn der Server zu antworten beginnt, dann aber hängt, wird das Zeitlimit nie erreicht. Aufgrund dieses Unterschieds ist der HttpClient von Apache die bessere Wahl.
BenvolioT
7

Ich fand das Einstellen der Timeout-Einstellungen in HttpConnectionParamsund HttpConnectionManagerlöste unseren Fall nicht. Wir können nur org.apache.commons.httpclientVersion 3.0.1 verwenden.

Am Ende habe ich ein verwendet java.util.concurrent.ExecutorService, um den HttpClient.executeMethod()Anruf zu überwachen .

Hier ist ein kleines, in sich geschlossenes Beispiel

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
quelle
6

Die genannte Methode mit den höchsten Up-Werten von Laz ist ab Version 4.3 veraltet. Daher ist es besser, das Request Config Object zu verwenden und dann den HTTP-Client zu erstellen

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

Mit dem PoolingHttpClientConnectionManager kann der Benutzer die maximale Standardanzahl von Verbindungen und die maximale Anzahl von Verbindungen pro Route festlegen. Ich habe es auf 306 bzw. 108 eingestellt. Die Standardwerte sind in den meisten Fällen nicht ausreichend.

Zum Festlegen des Zeitlimits : Ich habe das RequestConfig-Objekt verwendet. Sie können auch die Eigenschaft Verbindungsanforderungszeitlimit festlegen, um das Zeitlimit für das Warten auf die Verbindung vom Verbindungsmanager festzulegen.

Arun Thundyill Saseendran
quelle
5

Dies wurde bereits in einem Kommentar von Benvoliot oben erwähnt. Aber ich denke, es ist einen Beitrag auf höchstem Niveau wert, weil ich mich sicher am Kopf gekratzt habe. Ich poste dies für den Fall, dass es jemand anderem hilft.

Ich habe einen einfachen Testclient geschrieben und das CoreConnectionPNames.CONNECTION_TIMEOUTTimeout funktioniert in diesem Fall perfekt. Die Anforderung wird abgebrochen, wenn der Server nicht antwortet.

Innerhalb des Servercodes, den ich tatsächlich zu testen versuchte, tritt jedoch nie eine Zeitüberschreitung des identischen Codes auf.

Das Problem wurde für mich behoben, indem das Zeitlimit für die Socket-Verbindungsaktivität ( CoreConnectionPNames.SO_TIMEOUT) anstelle der HTTP-Verbindung ( CoreConnectionPNames.CONNECTION_TIMEOUT) geändert wurde.

Lesen Sie auch die Apache-Dokumente sorgfältig durch: http://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/org/apache/http/params/CoreConnectionPNames.html#CONNECTION_TIMEOUT

Beachten Sie das Bit, das sagt

Bitte beachten Sie, dass dieser Parameter nur auf Verbindungen angewendet werden kann, die an eine bestimmte lokale Adresse gebunden sind.

Ich hoffe, das erspart jemand anderem den ganzen Kopfkratzer, den ich durchgemacht habe. Das wird mich lehren, die Dokumentation nicht gründlich zu lesen!

Dan Haynes
quelle
2

Op gab später an, dass sie Apache Commons HttpClient 3.0.1 verwenden

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

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

Sie können auch Ihre erforderliche Auszeit definieren.

Mohammed Irfan Tirupattur
quelle