Час очікування весняного відпочинку


125

Я хотів би встановити тайм-аути підключення для послуги відпочинку, використовуваної моєю веб-програмою. Я використовую Spring's RestTemplate, щоб поговорити зі своєю службою. Я провів деякі дослідження, і знайшов і використав xml нижче (у своїй програмі xml), який, на мою думку, призначений для встановлення тайм-ауту. Я використовую Spring 3.0.

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

<bean id="RestOperations" class="org.springframework.web.client.RestTemplate">
    <constructor-arg>

      <bean class="org.springframework.http.client.CommonsClientHttpRequestFactory">
        <property name="readTimeout" value="${restURL.connectionTimeout}" />
      </bean>
    </constructor-arg>
</bean>

Здається, що я встановив readTimeout, я отримую наступне:

Мережевий кабель відключений: чекає близько 20 секунд і повідомляє наступний виняток:

org.springframework.web.client.ResourceAccessException: Помилка вводу / виводу: Нема маршруту до хосту: підключення; вкладений виняток - java.net.NoRouteToHostException: Немає маршруту до хоста: підключитися

URL-адреса неправильна, тому 404 повертається службою відпочинку: Чекає близько 10 секунд і повідомляє наступний виняток:

org.springframework.web.client.HttpClientErrorException: 404 Не знайдено

Мої вимоги потребують коротших тайм-аутів, тому мені потрібно мати змогу змінити їх. Будь-які ідеї щодо того, що я роблю неправильно?

Велике дякую.

Відповіді:


164

Для весняного завантаження> = 1,4

@Configuration
public class AppConfig
{
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) 
    {
        return restTemplateBuilder
           .setConnectTimeout(...)
           .setReadTimeout(...)
           .build();
    }
}

Для весняного завантаження <= 1,3

@Configuration
public class AppConfig
{
    @Bean
    @ConfigurationProperties(prefix = "custom.rest.connection")
    public HttpComponentsClientHttpRequestFactory customHttpRequestFactory() 
    {
        return new HttpComponentsClientHttpRequestFactory();
    }

    @Bean
    public RestTemplate customRestTemplate()
    {
        return new RestTemplate(customHttpRequestFactory());
    }
}

то у вашому application.properties

custom.rest.connection.connection-request-timeout=...
custom.rest.connection.connect-timeout=...
custom.rest.connection.read-timeout=...

Це працює , тому що HttpComponentsClientHttpRequestFactoryє державні сеттери connectionRequestTimeout, connectTimeoutі readTimeoutта @ConfigurationPropertiesвстановлює їх для вас.


Для Spring 4.1 або Spring 5 без використання Spring Boot@Configuration замістьXML

@Configuration
public class AppConfig
{
    @Bean
    public RestTemplate customRestTemplate()
    {
        HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
        httpRequestFactory.setConnectionRequestTimeout(...);
        httpRequestFactory.setConnectTimeout(...);
        httpRequestFactory.setReadTimeout(...);

        return new RestTemplate(httpRequestFactory);
    }
}

Гарний приклад! Будь ласка, видаліть непарне newзаяву в Spring Bootприкладі
StasKolodyuk

7
Зауважте, що після цієї конфігурації RestTemplate буде використовувати клієнт апаш http (для встановлення тайм-ауту). За замовчуванням потоки maxPerRoute пулу підключення клієнта Apache http - 5, а максимальна загальна кількість потоків - 10 (httpClient-4.5.2). Нам потрібно встановити це самостійно в деяких ситуаціях (наприклад, нам потрібно підключитися до багатьох хостів і потрібно більше підключень).
bluearrow

2
Зверніть увагу, connectionRequestTimeoutатрибут недоступний до 4.1.4. РЕЛІЗ
Taoufik Mohdit

Я спробував конфігурацію для Spring Boot> = 1.4 у Spring Boot> = 2.1.8, і не мав успіху. Я дотримувався цієї публікації ( zetcode.com/springboot/resttemplate ), щоб зробити цю конфігурацію.
Венло Полотто

@ ÂngeloPolotдля посилання, яке ви опублікували, дає такі самі поради, як і це рішення. У статті йдеться: "Як варіант, ми можемо використовувати RestTemplateBuilder для виконання цієї роботи".
dustin.schultz

76

Нарешті я це налагодив.

Я думаю, що факт, що в нашому проекті було дві різні версії банку "commons-httpclient", не допомагав. Після того як я розібрався, я виявив, що ти можеш зробити дві речі ...

У код можна вписати:

HttpComponentsClientHttpRequestFactory rf =
    (HttpComponentsClientHttpRequestFactory) restTemplate.getRequestFactory();
rf.setReadTimeout(1 * 1000);
rf.setConnectTimeout(1 * 1000);

Перший раз, коли цей код буде названий, він встановить тайм-аут для HttpComponentsClientHttpRequestFactoryкласу, який використовує RestTemplate. Тому всі наступні дзвінки, здійснені користувачем, RestTemplateбудуть використовувати налаштування тайм-ауту, визначені вище.

Або кращий варіант - це зробити:

<bean id="RestOperations" class="org.springframework.web.client.RestTemplate">
    <constructor-arg>
        <bean class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
            <property name="readTimeout" value="${application.urlReadTimeout}" />
            <property name="connectTimeout" value="${application.urlConnectionTimeout}" />
        </bean>
    </constructor-arg>
</bean>

Де я використовую RestOperationsінтерфейс у своєму коді та отримую значення тайм-ауту з файлу властивостей.


Таким чином, це встановлює тайм-аути для всіх дзвінків через цей шаблон відпочинку (який є однократним). Чи знаєте ви, чи можна контролювати тайм-аути на запит? (наприклад: 10 секунд для поштового дзвінка та 5 секунд для отримання дзвінка тощо)
codealsa

@ sardo. Де я використовую інтерфейс RestOperations у своєму коді. нам потрібно створити для цього явний інтерфейс?
декад

Ви сказали, що ви використовуєте Spring 3.0 - який я також застряг - але в 3.0 немає HttpComponentsClientHttpRequestFactory! Ви оновили весну?
Куцi

5
Наведений вище код не працює останньою весною. Це дає ClassCastExceptionjava.lang.ClassCastException: org.springframework.http.client.InterceptingClientHttpRequestFactory cannot be cast to org.springframework.http.client.HttpComponentsClientHttpRequestFactory
комюнітор

40

Це питання є першим посиланням на пошук Spring Boot, тому було б чудово розмістити тут рішення, рекомендоване в офіційній документації . Spring Boot має власну зручність боб RestTemplateBuilder :

@Bean
public RestTemplate restTemplate(
        RestTemplateBuilder restTemplateBuilder) {

    return restTemplateBuilder
            .setConnectTimeout(Duration.ofSeconds(500))
            .setReadTimeout(Duration.ofSeconds(500))
            .build();
}

Створення примірників RestTemplate вручну - це потенційно проблемний підхід, оскільки інші автоматично налаштовані боби не вводяться в створені вручну екземпляри.


2
Примітка весняним новачкам, як я: просто вписати це в @Configuration нічого не призведе. Цей метод вимагає, щоб у вас цей RestTemplate вводився десь, що використовує його як аргумент конструктору RestTemplateXhrTransport, який ви, у свою чергу, додасте до свого списку транспорту, який ви передаєте своєму SocksJSClient.
Ключовий поклад

setConnectTimeoutа деякі реалізації setReadTimeoutзастаріли
скривець

17

Ось мої 2 копійки. Нічого нового, але деякі пояснення, вдосконалення та новіший код.

За замовчуванням RestTemplateмає нескінченний час очікування. Існує два види тайм-аута: час очікування з'єднання та час очікування зчитування. Наприклад, я міг підключитися до сервера, але не зміг прочитати дані. Програма зависла, і ви не маєте поняття, що відбувається.

Я буду використовувати анотації, які в наші дні є кращими від XML.

@Configuration
public class AppConfig {

    @Bean
    public RestTemplate restTemplate() {

        var factory = new SimpleClientHttpRequestFactory();

        factory.setConnectTimeout(3000);
        factory.setReadTimeout(3000);

        return new RestTemplate(factory);
    }
}

Тут ми використовуємо SimpleClientHttpRequestFactoryдля встановлення з'єднання та читання тайм-аутів. Потім він передається конструктору RestTemplate.

@Configuration
public class AppConfig {

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {

        return builder
                .setConnectTimeout(Duration.ofMillis(3000))
                .setReadTimeout(Duration.ofMillis(3000))
                .build();
    }
}

У другому рішенні ми використовуємо RestTemplateBuilder. Також зауважте параметри двох методів: вони беруть Duration. Перевантажені методи, що займають безпосередньо мілісекунди, тепер застаріли.

Редагування Тестовано за допомогою Spring Boot 2.1.0 та Java 11.


Яку версію весни та java ви використовуєте?
orirab

2
Spring Boot 2.1.0 та Java 11. Для робочого прикладу ви можете ознайомитися з моїм підручником: zetcode.com/springboot/resttemplate
Ян Боднар

Пропоную додати це у відповідь
orirab

Дивіться сторінку github.com/spring-projects/spring-boot/blob/master/… . Він був доданий у Spring Boot 2.1.0.
Ян Боднар

Дякую @JanBodnar, ти підручник - це єдиний, хто добре працював на моєму весняному завантаженні 5.x
Венло Полотто

15

Ось дійсно простий спосіб встановити тайм-аут:

RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());

private ClientHttpRequestFactory getClientHttpRequestFactory() {
    int timeout = 5000;
    HttpComponentsClientHttpRequestFactory clientHttpRequestFactory =
      new HttpComponentsClientHttpRequestFactory();
    clientHttpRequestFactory.setConnectTimeout(timeout);
    return clientHttpRequestFactory;
}

0

У мене був аналогічний сценарій, але також потрібно було встановити проксі. Найпростіший спосіб, з якого я міг це зробити, - це розширити SimpleClientHttpRequestFactoryполегшення налаштування проксі (різні проксі для непрод. Проти прод.). Це все одно має працювати, навіть якщо вам не потрібен проксі. Потім у своєму розширеному класі я переосмислюю openConnection(URL url, Proxy proxy)метод, використовуючи той самий, що й джерело , але просто встановлюючи тайм-аути перед поверненням.

@Override
protected HttpURLConnection openConnection(URL url, Proxy proxy) throws IOException {
    URLConnection urlConnection = proxy != null ? url.openConnection(proxy) : url.openConnection();
    Assert.isInstanceOf(HttpURLConnection.class, urlConnection);
    urlConnection.setConnectTimeout(5000);
    urlConnection.setReadTimeout(5000);
    return (HttpURLConnection) urlConnection;
}

0

Щоб розширити відповідь на benscabbia :

private RestTemplate restCaller = new RestTemplate(getClientHttpRequestFactory());

private ClientHttpRequestFactory getClientHttpRequestFactory() {
    int connectionTimeout = 5000; // milliseconds
    int socketTimeout = 10000; // milliseconds
    RequestConfig config = RequestConfig.custom()
      .setConnectTimeout(connectionTimeout)
      .setConnectionRequestTimeout(connectionTimeout)
      .setSocketTimeout(socketTimeout)
      .build();
    CloseableHttpClient client = HttpClientBuilder
      .create()
      .setDefaultRequestConfig(config)
      .build();
    return new HttpComponentsClientHttpRequestFactory(client);
}

0
  1. Час очікування RestTemplate з SimpleClientHttpRequestFactory Для програмного перекриття властивостей таймауту ми можемо налаштувати клас SimpleClientHttpRequestFactory, як показано нижче.

Перезазначення тайм-ауту за допомогою SimpleClientHttpRequestFactory

//Create resttemplate
RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());

//Override timeouts in request factory
private SimpleClientHttpRequestFactory getClientHttpRequestFactory() 
{
    SimpleClientHttpRequestFactory clientHttpRequestFactory
                      = new SimpleClientHttpRequestFactory();
    //Connect timeout
    clientHttpRequestFactory.setConnectTimeout(10_000);

    //Read timeout
    clientHttpRequestFactory.setReadTimeout(10_000);
    return clientHttpRequestFactory;
}
  1. Час очікування RestTemplate з HttpComponentsClientHttpRequestFactory SimpleClientHttpRequestFactory допомагає встановити тайм-аут, але він є дуже обмеженим у функціональності та може не виявитися достатнім у додатках у режимі реального часу. У виробничому коді ми можемо захотіти використовувати HttpComponentsClientHttpRequestFactory, який підтримує бібліотеку клієнтів HTTP разом із шаблоном відпочинку.

HTTPClient надає інші корисні функції, такі як пул з'єднань, керування в режимі очікування тощо.

Докладніше: Spring RestTemplate + Приклад конфігурації HttpClient

Перезазначте тайм-аут із HttpComponentsClientHttpRequestFactory

//Create resttemplate
RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());

//Override timeouts in request factory
private SimpleClientHttpRequestFactory getClientHttpRequestFactory() 
{
    HttpComponentsClientHttpRequestFactory clientHttpRequestFactory
                      = new HttpComponentsClientHttpRequestFactory();
    //Connect timeout
    clientHttpRequestFactory.setConnectTimeout(10_000);

    //Read timeout
    clientHttpRequestFactory.setReadTimeout(10_000);
    return clientHttpRequestFactory;
}

довідка: Приклад конфігурації тайм-ауту Spring RestTemplate

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.