Spring RestTemplate超时


125

我想为我的Web应用程序使用的rest服务设置连接超时。我正在使用Spring的RestTemplate与我的服务交谈。我进行了一些研究,发现并使用了下面的xml(在我的应用程序xml中),我认为这是为了设置超时。我正在使用Spring 3.0。

我在这里也看到了同样的问题,使用RestTemplate为Spring Web服务设置超时,但是解决方案看起来并不干净,我更愿意通过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错误:主机没有路由:连接;嵌套的异常是java.net.NoRouteToHostException:没有路由到主机:connect

网址不正确,因此REST服务返回404: 等待大约10秒,并报告以下异常:

org.springframework.web.client.HttpClientErrorException:找不到404

我的要求需要更短的超时,因此我需要能够更改这些超时。关于我在做什么错的任何想法吗?

非常感谢。

Answers:


163

对于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有公共setter方法connectionRequestTimeoutconnectTimeout以及readTimeout@ConfigurationProperties套它们。


对于使用Spring Boot@Configuration而不是Spring Boot的Spring 4.1或Spring 5XML

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

        return new RestTemplate(httpRequestFactory);
    }
}

很好的例子!请删除示例中的奇怪new陈述Spring Boot
StasKolodyuk '16

7
请注意,完成此配置后,RestTemplate将使用apache http客户端(设置超时)。Apache http客户端连接池的默认maxPerRoute线程为5,最大线程总数为10(httpClient-4.5.2)。在某些情况下,我们需要自行设置(例如,我们需要连接到许多主机并且需要更多连接)。
bluearrow

2
请注意,该connectionRequestTimeout属性在4.1.4.RELEASE之前不可用
Taoufik Mohdit

我在Spring Boot> = 2.1.8上尝试了Spring Boot> = 1.4的配置,但没有成功。我关注了这篇文章( zetcode.com/springboot/resttemplate)进行了配置。
ngelo Polotto

@ÂngeloPolotto您发布的链接提供与此解决方案相同的建议。文章说:“或者,我们可以使用RestTemplateBuilder来完成这项工作。”
–ustin.schultz

76

我终于得到了这个工作。

我认为我们的项目具有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在代码中使用接口的位置,并从属性文件中获取超时值。


因此,这将设置通过此其余模板(单个)的所有呼叫的超时。您知道是否可以控制每个请求的超时时间吗?(例如:邮寄呼叫10秒,呼叫呼叫5秒等)
codealsa

@ sardo。我在代码中使用RestOperations接口的位置。我们需要为此创建任何显式接口吗?
死路一条

您说过您正在使用Spring 3.0(我也一直在使用它),但是在3.0中没有HttpComponentsClientHttpRequestFactory!您更新了Spring吗?
库奇(Kutzi)

5
上面的代码在最新的Spring中不起作用。它给出了ClassCastExceptionjava.lang.ClassCastException: org.springframework.http.client.InterceptingClientHttpRequestFactory cannot be cast to org.springframework.http.client.HttpComponentsClientHttpRequestFactory
comiventor '18

40

这个问题是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注入到手动创建的实例中。


2
给像我这样的Spring新手的笔记:将其粘贴在@Configuration中不会做任何事情。此方法要求您在此位置注入RestTemplate,并将其用作RestTemplateXhrTransport构造函数的参数,然后将其添加到传递给SocksJSClient的传输列表中。
Key Lay '18

setConnectTimeout和的某些实现已setReadTimeout被弃用
skryvets

17

这是我的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测试过。


您正在使用哪个spring和java版本?
orirab

2
Spring Boot 2.1.0和Java11
Jan Bodnar

我建议将此添加到答案中
orirab

参见github.com/spring-projects/spring-boot/blob/master/…。它是在Spring Boot 2.1.0中添加的。
Jan Bodnar

谢谢@JanBodnar,你教程是关于我的春节,引导5.x的唯一运作良好
安杰洛Polotto

15

这是设置超时的一种非常简单的方法:

RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());

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

0

我也有类似的情况,但是还需要设置代理。我能看到的最简单的方法是扩展,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;
}

0

扩大本斯卡比亚的答案:

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

0
  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. 带有HttpComponentsClientHttpRequestFactory的RestTemplate超时SimpleClientHttpRequestFactory有助于设置超时,但是它的功能非常有限,在实时应用程序中可能不够用。在生产代码中,我们可能想使用支持HTTP客户端库以及resttemplate的HttpComponentsClientHttpRequestFactory。

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超时配置示例

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.