我想为我的Web应用程序使用的休息服务设置连接超时。我正在使用Spring的RestTemplate与我的服务交谈。我做了一些研究,我发现并使用了下面的xml(在我的应用程序xml中),我认为这是为了设置超时。我正在使用Spring 3.0。
我在这里看到同样的问题Timeout configuration for spring webservices with RestTemplate但是解决方案似乎不是 clean ,我更喜欢通过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.ResourceAccessExcep tion:I / O错误:没有到主机的路由:connect;嵌套异常是java.net.NoRouteToHostException:没有到主机的路由:connect
网址不正确,因此休息服务返回404: 等待大约10秒钟并报告异常:
org.springframework.web.client.HttpClientErrorException:404 Not Found
我的要求需要更短的超时时间,因此我需要能够更改这些。关于我做错了什么的想法?
非常感谢。
答案 0 :(得分:128)
Spring Boot&gt; = 1.4
@Configuration
public class AppConfig
{
@Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder)
{
return restTemplateBuilder
.setConnectTimeout(...)
.setReadTimeout(...)
.build();
}
}
Spring Boot&lt; = 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 Boot的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);
}
}
答案 1 :(得分:67)
我终于有了这个工作。
我认为我们的项目有两个不同版本的commons-httpclient jar这一事实没有帮助。一旦我把它整理出来,我发现你可以做两件事......
在代码中,您可以输入以下内容:
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 :(得分:19)
这个问题是Spring Boot搜索的第一个链接,因此,很高兴将solution recommended in the official documentation置于此处。 Spring Boot有自己的便利bean RestTemplateBuilder:
@Bean
public RestTemplate restTemplate(
RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder
.setConnectTimeout(500)
.setReadTimeout(500)
.build();
}
手动创建RestTemplate实例是一种潜在的麻烦方法,因为其他自动配置的bean不会在手动创建的实例中注入。
答案 3 :(得分:12)
这是设置超时的一种非常简单的方法:
RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
private ClientHttpRequestFactory getClientHttpRequestFactory() {
int timeout = 5000;
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory =
new HttpComponentsClientHttpRequestFactory();
clientHttpRequestFactory.setConnectTimeout(timeout);
return clientHttpRequestFactory;
}
答案 4 :(得分:8)
这是我的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上进行了测试。
答案 5 :(得分:2)
使用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;
}
HTTPClient提供了其他有用的功能,例如连接池,空闲连接管理等。
了解更多:Spring RestTemplate + HttpClient configuration example
使用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;
}
答案 6 :(得分:0)
我有类似的情况,但也需要设置代理。我能看到的最简单的方法是扩展SimpleClientHttpRequestFactory
以便于设置代理(非prod与prod的不同代理)。即使您不需要代理,这仍然可以工作。然后在我的扩展课程中,我使用与source相同的方法覆盖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;
}
答案 7 :(得分:0)
展开benscabbia's答案:
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);
}