Запит клієнта Java HTTP із визначеним часом очікування


91

Я хотів би зробити 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("");
 }
}

- EDIT: Уточнити, яка бібліотека використовується -

Я використовую 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
HttpClient від Apache має два окремі тайм-аути: тайм-аут на час очікування встановлення TCP-з'єднання та окремий тайм-аут на час очікування наступного байта даних. HttpConnectionParams.setConnectionTimeout () - перший, HttpConnectionParams.setSoTimeout () - другий.
— benvolioT

7
Який тайм-аут за замовчуванням? Це 0 = нескінченно?
— Тобія

1
http.connection.timeout Integer Час очікування до встановлення з'єднання. Нульове значення означає, що час очікування не використовується.
— 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. Крім того, чи означає "за замовчуванням", що це за замовчуванням для всього, HttpClientщо HttpClientBuilderдасть build()метод from create () ? Або просто ті, що проходять через setDefaultRequestConfig(requestConfig)? Я маю сенс?
— ADTC

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

35

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

Я пропоную використовувати RequestConfig замість цього на своєму екземплярі HttpGet або HttpPost:

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

"використання коду вище" << 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
Це не вплине на час очікування для клієнта Apache HTTP.
— laz

9
Ніколи не стверджував, що так;)
— dbyrne

5
Поняття тайм-ауту HttpURLConnection недостатнє. Якщо сервер починає реагувати, але потім зависає, час очікування ніколи не досягається. HttpClient від Apache - кращий вибір через цю різницю.
— benvolioT

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

Про це вже згадувалося у коментарі бенволіота вище. Але, я думаю, це варто посади найвищого рівня, бо це, безсумнівно, змусило мене почухати голову. Я публікую це на випадок, якщо це допоможе комусь іншому.

Я написав простий тестовий клієнт і 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

Пізніше Op заявив, що вони використовують 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.