Запрос клиента 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.