Время ожидания Spring RestTemplate

Я хотел бы установить таймауты подключения для службы отдыха, используемой моим веб-приложением. Я использую Spring 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 не найдено

Мои требования требуют более коротких тайм-аутов, поэтому мне нужно иметь возможность их изменить. Есть идеи относительно того, что я делаю неправильно?

Большое спасибо.


person sardo    schedule 12.12.2012    source источник


Ответы (8)


Для Spring Boot> = 1.4

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

Для Spring Boot ‹= 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);
    }
}
person dustin.schultz    schedule 02.05.2016
comment
Хороший пример! Пожалуйста, удалите нечетный new оператор в Spring Boot примере - person StasKolodyuk; 21.10.2016
comment
Обратите внимание, что после этой конфигурации RestTemplate будет использовать http-клиент apache (для установки тайм-аута). Количество потоков maxPerRoute по умолчанию для пула подключений клиентов Apache http составляет 5, а максимальное общее количество потоков - 10 (httpClient-4.5.2). Нам нужно установить это самостоятельно в некоторых ситуациях (например, нам нужно подключиться ко многим хостам и нам нужно больше подключений). - person bluearrow; 26.12.2017
comment
Обратите внимание, что атрибут connectionRequestTimeout недоступен до версии 4.1.4. - person Taoufik Mohdit; 06.08.2018
comment
Я попробовал конфигурацию Spring Boot ›= 1.4 на Spring Boot› = 2.1.8, и у меня ничего не вышло. Я следил за этим сообщением (zetcode.com/springboot/resttemplate), чтобы настроить эту конфигурацию. - person Ângelo Polotto; 22.10.2019
comment
@ ÂngeloPolotto размещенная вами ссылка дает тот же совет, что и это решение. В статье говорится: в качестве альтернативы мы можем использовать RestTemplateBuilder для выполнения этой работы. - person dustin.schultz; 15.11.2019
comment
@ dustin.schultz, какое значение по умолчанию? - person Artanis Zeratul; 23.03.2021

Наконец-то я получил эту работу.

Я думаю, что тот факт, что в нашем проекте были две разные версии jar-файла 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 в своем коде и получаю значения тайм-аута из файла свойств.

person sardo    schedule 26.02.2013
comment
Таким образом, это устанавливает тайм-ауты для всех вызовов через этот шаблон отдыха (который является одиночным). Знаете ли вы, можно ли контролировать тайм-ауты для каждого запроса? (например: 10 секунд для пост-звонка и 5 секунд для получения звонка и т. д.) - person codesalsa; 21.04.2016
comment
@ sardo. Где я использую интерфейс RestOperations в своем коде. нам нужно создать для этого какой-то явный интерфейс? - person deadend; 11.05.2017
comment
Вы сказали, что используете Spring 3.0, с которым я тоже застрял, но в 3.0 нет HttpComponentsClientHttpRequestFactory! Вы обновляли Spring? - person Kutzi; 01.06.2017
comment
Приведенный выше код не работает в последней версии Spring. Это дает ClassCastException java.lang.ClassCastException: org.springframework.http.client.InterceptingClientHttpRequestFactory cannot be cast to org.springframework.http.client.HttpComponentsClientHttpRequestFactory - person comiventor; 22.02.2018

Этот вопрос является первой ссылкой для поиска Spring Boot, поэтому было бы здорово разместить здесь решение, рекомендованное в официальной документации. Spring Boot имеет собственный компонент удобства RestTemplateBuilder:

@Bean
public RestTemplate restTemplate(
        RestTemplateBuilder restTemplateBuilder) {

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

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

person heldev    schedule 27.10.2017
comment
Примечание для новичков Spring, таких как я: просто вставка этого в @Configuration ничего не даст. Этот метод требует, чтобы вы внедрили этот RestTemplate в какое-то место, которое использует его в качестве аргумента конструктора RestTemplateXhrTransport, который вы, в свою очередь, добавите в свой список транспортов, который вы передаете своему SocksJSClient. - person Key Lay; 27.02.2018
comment
setConnectTimeout и некоторые реализации setReadTimeout устарели - person skryvets; 10.07.2019

Вот мои 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.

person Jan Bodnar    schedule 27.11.2018
comment
Какую версию Spring и Java вы используете? - person orirab; 27.12.2018
comment
Spring Boot 2.1.0 и Java 11. В качестве рабочего примера вы можете взглянуть на мой учебник: zetcode. com / springboot / resttemplate - person Jan Bodnar; 27.12.2018
comment
Предлагаю добавить это к ответу - person orirab; 27.12.2018
comment
См. github.com/spring-projects/spring-boot/blob/master/. Он был добавлен в Spring Boot 2.1.0. - person Jan Bodnar; 16.01.2019
comment
Спасибо @JanBodnar, ваше руководство - единственное, что хорошо сработало на моем Spring Boot 5.x - person Ângelo Polotto; 22.10.2019

Вот действительно простой способ установить тайм-аут:

RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());

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

  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 вместе с resttemplate.

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

person Zgpeace    schedule 03.06.2020

У меня был аналогичный сценарий, но также требовалось установить прокси. Самый простой способ, которым я мог это сделать, - это расширить SimpleClientHttpRequestFactory, чтобы упростить настройку прокси (разные прокси для non-prod и prod). Это все равно должно работать, даже если вам не нужен прокси. Затем в моем расширенном классе я переопределяю метод openConnection(URL url, Proxy proxy), используя тот же метод, что и source, но просто установив время ожидания перед возвратом.

@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;
}
person Ryan D    schedule 04.10.2017

Чтобы расширить ответ 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);
}
person Tasos Zervos    schedule 11.04.2020