Запрос клиента HTTP Java с заданным таймаутом


92

Я хотел бы сделать BIT (встроенные тесты) для ряда серверов в моем облаке. Мне нужно, чтобы запрос завершился ошибкой при большом тайм-ауте.

Как мне сделать это с помощью java?

Попытка сделать что-то подобное ниже, похоже, не работает.

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

- РЕДАКТИРОВАТЬ: уточнить, какая библиотека используется -

Я использую httpclient из apache, вот соответствующий раздел pom.xml

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

Какую библиотеку вы используете для всех функций HTTP?
— nojo

Спасибо за комментарий. Я обновил свой пост.
— Максим Векслер

Ответы:


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
Что это значит? Тайм-аут чего он выставил? См. Stackoverflow.com/questions/3000767/…
— Максим Векслер

84
У Apache HttpClient есть два отдельных таймаута: тайм-аут, указывающий, как долго ждать установления TCP-соединения, и отдельный тайм-аут, как долго ждать следующего байта данных. HttpConnectionParams.setConnectionTimeout () - это первое, HttpConnectionParams.setSoTimeout () - второе.
— benvolioT 09

7
Какой тайм-аут по умолчанию? 0 = бесконечно?
— Tobia

1
http.connection.timeout Целое число Время ожидания до установления соединения. Нулевое значение означает, что тайм-аут не используется.
— maveroid

26
Будущим читателям: следует отметить, что упомянутые здесь классы теперь устарели (по состоянию на 05.07.2016), хотя, вероятно, это был хороший ответ, когда он был опубликован в 2010 году. См. Этот ответ: stackoverflow.com/a/ 19153314/192801 для чего-нибудь более современного.
— FrustratedWithFormsDesigner

125

Если вы используете Http Client версии 4.3 и выше, вам следует использовать следующее:

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

4
Благодарность! Я потратил по крайней мере 20 минут на то, чтобы понять, как избавиться от устаревших команд, прежде чем найти ваш ответ.
— vextorspace

Забыл SocketTimeout. Кроме того, означает ли "default" это значение по умолчанию для всего, HttpClientчто HttpClientBuilderпередаст build()метод from create () ? Или только те, которые проходят setDefaultRequestConfig(requestConfig)? Я понимаю?
— ADTC

@ADTC Ваш вопрос немного сбивает с толку :). Конфигурация запроса по умолчанию будет использоваться для всех экземпляров HttpPost, HttpGet, ..., использующих только этот HttpClient. Если вы создали другой экземпляр HttpClient, эта конфигурация запроса не будет использоваться с этим клиентом.
— Thunder

35

HttpParams устарел в новой библиотеке Apache HTTPClient. Использование кода, предоставленного Laz, приводит к предупреждению об устаревании.

Я предлагаю вместо этого использовать RequestConfig в вашем экземпляре HttpGet или HttpPost:

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

"using the code above" << SO - это не форум, и ответы меняются вверх / вниз из-за нескольких факторов, поэтому мы не знаем, какой код вы имеете в виду. Не могли бы вы сказать что-то вроде «используя код из ответа xyz»?
— ADTC

4
Кстати, аккуратный ответ. Но по сравнению с ответом Thunder, в чем разница между установкой RequestConfigв каждый HttpPostи по умолчанию в HttpClient?
— ADTC

2
Да, вы правы, приведенный выше код относится к «принятому ответу», который не должен меняться со временем. Я все равно
— обновлю

10

Похоже, вы используете HttpClient API, о котором я ничего не знаю, но вы можете написать что-то подобное, используя ядро ​​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;
}

2
Это не повлияет на тайм-аут для HTTP-клиента Apache.
— laz

9
Никогда не утверждал, что это сделал;)
— dbyrne 09

5
Понятие тайм-аута в HttpURLConnection недостаточно. Если сервер начинает отвечать, но затем зависает, таймаут никогда не достигается. HttpClient от Apache - лучший выбор из-за этой разницы.
— benvolioT 09

7

Я обнаружил , что установка времени из настроек в HttpConnectionParamsи HttpConnectionManagerне решало наше дело. Мы ограничены использованием org.apache.commons.httpclientверсии 3.0.1.

В итоге я использовал java.util.concurrent.ExecutorServiceдля отслеживания HttpClient.executeMethod()звонка.

Вот небольшой автономный пример

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

Указанный метод с наивысшими показателями Laz устарел начиная с версии 4.3. Следовательно, было бы лучше использовать объект конфигурации запроса, а затем создать 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 позволяет пользователю установить максимальное количество подключений по умолчанию и максимальное количество подключений на маршрут. Я установил 306 и 108 соответственно. В большинстве случаев значений по умолчанию будет недостаточно.

Для установки тайм-аута: я использовал объект RequestConfig. Вы также можете установить свойство Connection Request Timeout для установки тайм-аута ожидания соединения от диспетчера соединений.


5

Об этом уже упоминалось в комментарии Benvoliot выше. Но я думаю, что это стоит поста на высшем уровне, потому что он наверняка заставил меня почесать голову. Я отправляю это на случай, если это поможет кому-то другому.

Я написал простой тестовый клиент, и CoreConnectionPNames.CONNECTION_TIMEOUTв этом случае тайм-аут отлично работает. Запрос отменяется, если сервер не отвечает.

Однако внутри серверного кода, который я пытался протестировать, время ожидания идентичного кода никогда не истекло.

Изменение его на тайм-аут для активности соединения сокета ( CoreConnectionPNames.SO_TIMEOUT) вместо HTTP-соединения ( CoreConnectionPNames.CONNECTION_TIMEOUT) устранило проблему для меня.

Также внимательно прочтите документы Apache: http://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/org/apache/http/params/CoreConnectionPNames.html#CONNECTION_TIMEOUT

Обратите внимание на бит, который говорит

Обратите внимание, что этот параметр может применяться только к соединениям, привязанным к определенному локальному адресу.

Я надеюсь, что это избавит кого-то от всей моей боли в голове. Это научит меня не читать документацию досконально!


2

Позже Оп заявил, что они использовали Apache Commons HttpClient 3.0.1.

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.