Spring RestTemplate超时

时间:2012-12-12 09:50:07

标签: spring rest timeout resttemplate

我想为我的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

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

非常感谢。

8 个答案:

答案 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有公开制定者connectionRequestTimeoutconnectTimeoutreadTimeout@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)

  1. RestTemplate与SimpleClientHttpRequestFactory超时 要以编程方式覆盖超时属性,我们可以如下自定义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. RestTemplate与HttpComponentsClientHttpRequestFactory超时 SimpleClientHttpRequestFactory有助于设置超时,但功能非常有限,在实时应用程序中可能不够用。在生产代码中,我们可能要使用支持HTTP客户端库以及resttemplate的HttpComponentsClientHttpRequestFactory。

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

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