Spring Тайм-аут RestTemplate
Я хотел бы установить таймауты подключения для службы отдыха, используемой моим веб-приложением. Я использую Spring RestTemplate, чтобы поговорить с моей службой. Я провел некоторое исследование, и я нашел и использовал xml ниже (в моем приложении xml), который, как мне кажется, предназначен для установки таймаута. Я использую Spring 3.0.
Я также видел ту же проблему здесь Конфигурация тайм-аута для Spring веб-сервисов с RestTemplate, но решения не кажутся такими чистыми, я бы предпочел установите значения таймаута через Spring config
<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: Ошибка ввода-вывода: нет пути к хосту: connect; Вложенное исключение - это java.net.NoRouteToHostException: нет пути к хосту: connect
URL неправильный, поэтому 404 возвращен службой отдыха:
Ожидает около 10 секунд и сообщает следующее исключение:
org.springframework.web.client.HttpClientErrorException: 404 Не найдено
Мои требования требуют более коротких тайм-аутов, поэтому мне нужно их изменить. Любые идеи относительно того, что я делаю неправильно?
Большое спасибо.
Ответы
Ответ 1
Наконец-то я получил эту работу.
Я думаю, что тот факт, что наш проект имел две разные версии банды 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
в своем коде и получаю значения таймаута из файла свойств.
Ответ 2
Для весенней загрузки> = 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);
}
}
Ответ 3
Этот вопрос является первой ссылкой для поиска в Spring Boot, поэтому было бы здорово разместить здесь решение, рекомендованное в официальной документации. Spring Boot имеет собственный удобный bean-компонент RestTemplateBuilder:
@Bean
public RestTemplate restTemplate(
RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder
.setConnectTimeout(Duration.ofSeconds(500))
.setReadTimeout(Duration.ofSeconds(500))
.build();
}
Ручное создание экземпляров RestTemplate является потенциально проблематичным подходом, поскольку другие автоматически настраиваемые bean-компоненты не вводятся в созданные вручную экземпляры.
Ответ 4
Вот простой способ установить таймаут:
RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
private ClientHttpRequestFactory getClientHttpRequestFactory() {
int timeout = 5000;
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory =
new HttpComponentsClientHttpRequestFactory();
clientHttpRequestFactory.setConnectTimeout(timeout);
return clientHttpRequestFactory;
}
Ответ 5
Вот мои 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
чтобы установить соединение и время 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
. Перегруженные методы, которые занимают непосредственно миллисекунды, теперь устарели.
Edit Испытано с Spring ботинке 2.1.0 и Java 11.
Ответ 6
У меня был похожий сценарий, но также требовалось установить прокси. Самый простой способ, которым я мог это сделать, - расширить SimpleClientHttpRequestFactory
для упрощения настройки прокси (разные прокси для non-prod vs 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;
}