155

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

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

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

我的要求需要更短的超时,所以我需要能够更改这些。关于我做错了什么的任何想法?

非常感谢。

4

9 回答 9

206

对于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有 public setter connectionRequestTimeout,connectTimeoutreadTimeoutand@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);
    }
}
于 2016-05-02T21:09:04.853 回答
79

我终于得到了这个工作。

我认为我们的项目有两个不同版本的 commons-httpclient jar 并没有帮助。一旦我整理出来,我发现你可以做两件事......

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

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

第一次调用此代码时,它将HttpComponentsClientHttpRequestFactoryRestTemplate. 因此,所有后续调用都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接口并从属性文件中获取超时值。

于 2013-02-26T15:32:51.680 回答
56

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

于 2017-10-27T01:52:25.877 回答
27

这是我的 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 进行编辑测试。

于 2018-11-27T12:16:24.737 回答
17

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

RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());

private ClientHttpRequestFactory getClientHttpRequestFactory() {
    int timeout = 5000;
    HttpComponentsClientHttpRequestFactory clientHttpRequestFactory =
      new HttpComponentsClientHttpRequestFactory();
    clientHttpRequestFactory.setConnectTimeout(timeout);
    return clientHttpRequestFactory;
}
于 2016-05-26T19:43:33.010 回答
6
  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 客户端库的 HttpComponentsClientHttpRequestFactory 以及 resttemplate。

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

于 2020-06-03T01:34:57.083 回答
0

我有类似的情况,但也需要设置代理。我能看到的最简单的方法是扩展,SimpleClientHttpRequestFactory以便于设置代理(非产品与产品的不同代理)。即使您不需要代理,这仍然可以工作。然后在我的扩展类中,我使用与sourceopenConnection(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;
}
于 2017-10-04T15:10:10.267 回答
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);
}
于 2020-04-11T17:55:20.950 回答
0
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));
}
于 2021-11-05T03:28:08.740 回答