Spring RestTemplate 超时
Posted
技术标签:
【中文标题】Spring RestTemplate 超时【英文标题】:Spring RestTemplate timeout 【发布时间】:2012-11-29 23:52:49 【问题描述】:我想为我的 Web 应用程序使用的休息服务设置连接超时。我正在使用 Spring 的 RestTemplate 与我的服务交谈。我做了一些研究,发现并使用了下面的 xml(在我的应用程序 xml 中),我相信它是为了设置超时。我正在使用 Spring 3.0。
我在这里Timeout configuration for spring webservices with 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: I/O error: No route to host: connect;嵌套异常是 java.net.NoRouteToHostException: No route to host: connect
Url 不正确,rest 服务返回 404: 等待大约 10 秒并报告以下异常:
org.springframework.web.client.HttpClientErrorException: 404 Not Found
我的要求需要更短的超时,所以我需要能够更改这些。关于我做错了什么有什么想法吗?
非常感谢。
【问题讨论】:
【参考方案1】: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));
【讨论】:
【参考方案2】:-
使用 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;
-
使用 HttpComponentsClientHttpRequestFactory 的 RestTemplate 超时
SimpleClientHttpRequestFactory 有助于设置超时,但它的功能非常有限,在实时应用程序中可能不够用。在生产代码中,我们可能希望使用支持 HTTP 客户端库的 HttpComponentsClientHttpRequestFactory 以及 resttemplate。
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;
参考:Spring RestTemplate timeout configuration example
【讨论】:
【参考方案3】:扩展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);
【讨论】:
【参考方案4】:这个问题是 Spring Boot 搜索的第一个链接,因此,最好将solution recommended in the official documentation 放在这里。 Spring Boot有自己的便利豆RestTemplateBuilder:
@Bean
public RestTemplate restTemplate(
RestTemplateBuilder restTemplateBuilder)
return restTemplateBuilder
.setConnectTimeout(Duration.ofSeconds(500))
.setReadTimeout(Duration.ofSeconds(500))
.build();
手动创建 RestTemplate 实例是一种潜在的麻烦方法,因为其他自动配置的 bean 没有被注入到手动创建的实例中。
【讨论】:
给像我这样的 Spring 新手的注意事项:仅将其粘贴在 @Configuration 中不会做任何事情。此方法要求您将这个 RestTemplate 注入 somwhere,将其用作 RestTemplateXhrTransport 的构造函数的参数,然后将其添加到传递给 SocksJSClient 的传输列表中。setConnectTimeout
和 setReadTimeout
的一些实现已弃用【参考方案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
来设置连接和读取超时。
然后传递给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 测试。
【讨论】:
【参考方案6】:对于 Spring Boot >= 1.4
@Configuration
public class AppConfig
@Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder)
return restTemplateBuilder
.setConnectTimeout(...)
.setReadTimeout(...)
.build();
对于 Spring Boot
@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 Boot 的 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);
【讨论】:
很好的例子!请删除Spring Boot
示例中奇怪的 new
语句
请注意,在此配置后,RestTemplate 将使用 apache http 客户端(设置超时)。 Apache http 客户端连接池的默认 maxPerRoute 线程数为 5,最大总线程数为 10 (httpClient-4.5.2)。在某些情况下我们需要自己设置(比如我们需要连接很多主机,需要更多的连接)。
请注意 connectionRequestTimeout
属性在 4.1.4.RELEASE 之前不可用
我在 Spring Boot >= 2.1.8 上尝试了 Spring Boot >= 1.4 的配置,但没有成功。我按照这篇文章 (zetcode.com/springboot/resttemplate) 进行了配置。
@ÂngeloPolotto 您发布的链接提供了与此解决方案相同的建议。文章说:“或者,我们可以使用 RestTemplateBuilder 来完成这项工作。”【参考方案7】:
我有类似的情况,但也需要设置代理。我能看到的最简单的方法是扩展 SimpleClientHttpRequestFactory
以便于设置代理(非产品与产品的不同代理)。即使您不需要代理,这仍然可以工作。然后在我的扩展类中,我覆盖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;
【讨论】:
【参考方案8】:这是设置超时的一个非常简单的方法:
RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
private ClientHttpRequestFactory getClientHttpRequestFactory()
int timeout = 5000;
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory =
new HttpComponentsClientHttpRequestFactory();
clientHttpRequestFactory.setConnectTimeout(timeout);
return clientHttpRequestFactory;
【讨论】:
【参考方案9】:我终于搞定了。
我认为我们的项目有两个不同版本的 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
接口并从属性文件中获取超时值。
【讨论】:
所以这设置了通过这个休息模板(这是一个单例)的所有调用的超时时间。您知道是否可以控制每个请求的超时时间? (例如:post call 10 秒,get call 等 5 秒) @sardo。我在代码中使用 RestOperations 接口的地方。我们需要为此创建任何显式接口吗? 您说您使用的是 Spring 3.0——我也坚持使用它——但在 3.0 中没有 HttpComponentsClientHttpRequestFactory!你更新 Spring 了吗? 以上代码在最新的 Spring 中不起作用。它给 ClassCastExceptionjava.lang.ClassCastException: org.springframework.http.client.InterceptingClientHttpRequestFactory cannot be cast to org.springframework.http.client.HttpComponentsClientHttpRequestFactory
以上是关于Spring RestTemplate 超时的主要内容,如果未能解决你的问题,请参考以下文章
(030)Spring Boot之RestTemplate访问web服务案例
由于未绑定的 RestTemplate,Spring-Boot RestClientTest 无法正确自动配置 MockRestServiceServer