Spring RestTemplate 超时

我想为我的 Web 应用程序使用的一个休息服务设置连接超时。我正在使用 Spring 的 RestTemplate与我的服务通话。我做了一些研究,找到并使用了下面的 xml (在我的应用程序 xml 中) ,我相信它是用来设置超时的。我用的是 Spring 3.0。

我在这里也看到了同样的问题 使用 RestTemplate 的 Spring webservices 的超时配置,但是解决方案似乎不像 干净,我更喜欢通过 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秒,并报告以下异常:

I/O 错误: 没有到 host: connect 的路由; 嵌套异常是 java.net.NoRouteToHostException: 没有到 host: connect 的路由

Url 不正确,因此404通过休息服务返回: 等待约10秒,并报告以下异常:

未找到

我的需求需要更短的超时时间,所以我需要能够更改这些。知道我哪里做错了吗?

非常感谢。

344621 次浏览

我终于把它修好了。

我认为我们的项目有两个不同版本的 commons-httpclient jar 这一事实没有帮助。一旦我解决了这个问题,我发现你可以做两件事..。

在代码中,可以输入以下内容:

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

第一次调用此代码时,它将设置 RestTemplate使用的 HttpComponentsClientHttpRequestFactory类的超时时间。因此,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接口,并从属性文件中获取超时值。

对于 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有公共设置器 connectionRequestTimeoutconnectTimeoutreadTimeout,而 @ConfigurationProperties为您设置它们。


对于 没有 Spring 引导的 Spring 4.1或 Spring 5使用 @Configuration而不是 XML

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


return new RestTemplate(httpRequestFactory);
}
}

下面是一个非常简单的设置超时的方法:

RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());


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

我有一个类似的场景,但是还需要设置一个代理。我认为实现这一点的最简单方法是扩展 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;
}

这个问题是 SpringBoot 搜索的第一个链接,因此,最好把 正式文件所建议的解决方案放在这里。Spring Boot 有自己的便利 bean RestTemplateBuilder:

@Bean
public RestTemplate restTemplate(
RestTemplateBuilder restTemplateBuilder) {


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

手动创建 RestTemplate 实例是一种潜在的麻烦方法,因为没有在手动创建的实例中注入其他自动配置的 bean。

这是我的建议。没有什么新的,但是一些解释,改进和更新的代码。

默认情况下,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。直接采用毫秒的重载方法现在已不推荐使用。

剪辑 使用 SpringBoot2.1.0和 Java11进行测试。

详细介绍 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);
}
  1. 使用 SimpleClientHttpRequestFactory 的 RestTemplate 超时 若要以编程方式重写超时属性,可以按以下方式自定义 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. 使用 HttpContentsClientHttpRequestFactory 的 RestTemplate 超时 SimpleClientHttpRequestFactory 有助于设置超时,但其功能非常有限,在实时应用程序中可能证明不够。在生产代码中,我们可能希望使用 HttpContentsClientHttpRequestFactory,它与 resttemplate 一起支持 HTTP 客户端库。

HTTPClient 提供了其他有用的特性,如连接池、空闲连接管理等。

延伸阅读: Spring RestTemplate + HttpClient 配置示例

用 HttpComponent 重写超时

//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;
}

参考资料: SpringRestTemplate 超时配置示例

private static RestTemplate restTemplate;


static {
HttpComponentsClientHttpRequestFactory rf = new HttpComponentsClientHttpRequestFactory();
rf.setReadTimeout(3 * 1000);
rf.setConnectTimeout(2 * 1000);


restTemplate = new RestTemplate(rf);
restTemplate.getMessageConverters()
.add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));
}

RestTemplate 的简单超时。我将读写超时设置为3秒。

@Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder){
RestTemplate restTemplate= restTemplateBuilder.setConnectTimeout(Duration.ofMillis(3000)).setReadTimeout(Duration.ofMillis(3000)).build();
return restTemplate;


}