Thời gian chờ Spring RestTemplate


125

Tôi muốn đặt thời gian chờ kết nối cho dịch vụ nghỉ được ứng dụng web của tôi sử dụng. Tôi đang sử dụng RestTemplate của Spring để nói chuyện với dịch vụ của mình. Tôi đã thực hiện một số nghiên cứu và tôi đã tìm thấy và sử dụng xml bên dưới (trong xml ứng dụng của tôi) mà tôi tin rằng dùng để đặt thời gian chờ. Tôi đang sử dụng Spring 3.0.

Tôi cũng đã gặp vấn đề tương tự ở đây Cấu hình thời gian chờ cho các thiết bị web mùa xuân với RestTemplate nhưng các giải pháp có vẻ không rõ ràng lắm , tôi muốn đặt giá trị thời gian chờ thông qua cấu hình Spring

<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>

Có vẻ như bất cứ điều gì tôi đặt readTimeout là tôi nhận được như sau:

Cáp mạng bị ngắt kết nối: Chờ khoảng 20 giây và báo cáo ngoại lệ sau:

org.springframework.web.client.ResourceAccessExcep tion: Lỗi I / O: Không có đường dẫn đến máy chủ: kết nối; ngoại lệ lồng nhau là java.net.NoRouteToHostException: Không có đường dẫn đến máy chủ: kết nối

Url không chính xác nên 404 do dịch vụ nghỉ ngơi trả lại: Chờ khoảng 10 giây và báo cáo ngoại lệ sau:

org.springframework.web.client.HttpClientErrorException: 404 Không tìm thấy

Yêu cầu của tôi yêu cầu thời gian chờ ngắn hơn nên tôi cần có thể thay đổi những điều này. Bất kỳ ý tưởng nào về những gì tôi đang làm sai?

Cảm ơn nhiều.

Câu trả lời:


164

Đối với Spring Boot> = 1.4

@Configuration
public class AppConfig
{
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) 
    {
        return restTemplateBuilder
           .setConnectTimeout(...)
           .setReadTimeout(...)
           .build();
    }
}

Đối với 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());
    }
}

sau đó trong của bạn application.properties

custom.rest.connection.connection-request-timeout=...
custom.rest.connection.connect-timeout=...
custom.rest.connection.read-timeout=...

Này hoạt động vì HttpComponentsClientHttpRequestFactorycó setters công cộng connectionRequestTimeout, connectTimeoutreadTimeout@ConfigurationPropertiesbộ chúng cho bạn.


Đối với Spring 4.1 hoặc Spring 5 không có Spring Boot, sử dụng @Configurationthay vìXML

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

        return new RestTemplate(httpRequestFactory);
    }
}

Ví dụ đẹp! Xin vui lòng, loại bỏ lẻ newtuyên bố trong Spring Bootví dụ
StasKolodyuk

7
Lưu ý rằng sau cấu hình này, RestTemplate sẽ sử dụng máy khách apache http (để đặt thời gian chờ). Chủ đề maxPerRoute mặc định của nhóm kết nối máy khách Apache http là 5 và tổng số luồng tối đa là 10 (httpClient-4.5.2). Chúng tôi cần tự thiết lập điều này trong một số tình huống (chẳng hạn như chúng tôi cần kết nối với nhiều máy chủ và cần nhiều kết nối hơn).
bluearrow

2
Xin lưu ý connectionRequestTimeoutrằng thuộc tính không khả dụng trước 4.1.4. RELEASE
Taoufik Mohdit,

Tôi đã thử cấu hình For Spring Boot> = 1.4 trên Spring Boot> = 2.1.8 và không thành công. Tôi đã theo dõi bài đăng này ( zetcode.com/springboot/resttemplate ) để tạo cấu hình đó.
Ângelo Polotto

@ ÂngeloPolotto liên kết bạn đã đăng đưa ra lời khuyên tương tự như giải pháp này. Bài báo viết: "Ngoài ra, chúng ta có thể sử dụng RestTemplateBuilder để thực hiện công việc."
dustin.schultz

76

Cuối cùng tôi đã làm việc này.

Tôi nghĩ rằng thực tế là dự án của chúng tôi có hai phiên bản khác nhau của bình commons-httpclient không hữu ích. Sau khi sắp xếp xong, tôi thấy bạn có thể làm được hai điều ...

Trong mã, bạn có thể đặt như sau:

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

Lần đầu tiên mã này được gọi, nó sẽ đặt thời gian chờ cho HttpComponentsClientHttpRequestFactorylớp được sử dụng bởi RestTemplate. Do đó, tất cả các cuộc gọi tiếp theo được thực hiện bởi RestTemplatesẽ sử dụng cài đặt thời gian chờ được xác định ở trên.

Hoặc tùy chọn tốt hơn là làm điều này:

<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>

Nơi tôi sử dụng RestOperationsgiao diện trong mã của mình và nhận các giá trị thời gian chờ từ tệp thuộc tính.


Vì vậy, điều này đặt thời gian chờ cho tất cả các cuộc gọi thông qua mẫu phần còn lại này (là một singleton). Bạn có biết liệu có thể kiểm soát thời gian chờ theo yêu cầu không? (ví dụ: 10 giây cho một bài gọi và 5 giây cho một cuộc gọi get vv)
codesalsa

@ sardo. Nơi tôi sử dụng giao diện RestOperations trong mã của mình. chúng ta cần tạo bất kỳ giao diện rõ ràng nào cho việc này?
cụt

Bạn nói rằng bạn đang sử dụng Spring 3.0 - cái mà tôi cũng đang mắc kẹt - nhưng trong 3.0 không có HttpComponentsClientHttpRequestFactory! Bạn đã cập nhật Spring?
Kutzi

5
Mã trên không hoạt động trong Mùa xuân mới nhất. Nó cung cấp cho ClassCastExceptionjava.lang.ClassCastException: org.springframework.http.client.InterceptingClientHttpRequestFactory cannot be cast to org.springframework.http.client.HttpComponentsClientHttpRequestFactory
comiventor 22/02

40

Câu hỏi này là liên kết đầu tiên cho một tìm kiếm Spring Boot, do đó, sẽ rất tuyệt nếu đặt ở đây giải pháp được đề xuất trong tài liệu chính thức . Spring Boot có bean RestTemplateBuilder tiện lợi của riêng nó :

@Bean
public RestTemplate restTemplate(
        RestTemplateBuilder restTemplateBuilder) {

    return restTemplateBuilder
            .setConnectTimeout(Duration.ofSeconds(500))
            .setReadTimeout(Duration.ofSeconds(500))
            .build();
}

Việc tạo thủ công các cá thể RestTemplate là một cách tiếp cận có thể gây rắc rối vì các bean được cấu hình tự động khác không được đưa vào các phiên bản được tạo thủ công.


2
Một lưu ý cho những người mới đến Spring như tôi: chỉ cần gắn cái này vào @Configuration sẽ không làm được gì cả. Phương thức này yêu cầu bạn phải tiêm RestTemplate này vào nơi sử dụng nó làm đối số cho phương thức khởi tạo của RestTemplateXhrTransport mà bạn sẽ lần lượt thêm vào Danh sách các phương tiện truyền tải mà bạn chuyển đến SocksJSClient của mình.
Key Lay

setConnectTimeoutvà một số triển khai của setReadTimeoutkhông được dùng nữa
skryvets

17

Đây là 2 xu của tôi. Không có gì mới, nhưng một số giải thích, cải tiến và mã mới hơn.

Theo mặc định, RestTemplatecó thời gian chờ vô hạn. Có hai loại thời gian chờ: thời gian chờ kết nối và thời gian chờ đọc. Ví dụ: tôi có thể kết nối với máy chủ nhưng tôi không thể đọc dữ liệu. Ứng dụng bị treo và bạn không biết điều gì đang xảy ra.

Tôi sẽ sử dụng các chú thích, mà ngày nay được ưa chuộng hơn XML.

@Configuration
public class AppConfig {

    @Bean
    public RestTemplate restTemplate() {

        var factory = new SimpleClientHttpRequestFactory();

        factory.setConnectTimeout(3000);
        factory.setReadTimeout(3000);

        return new RestTemplate(factory);
    }
}

Ở đây chúng tôi sử dụng SimpleClientHttpRequestFactoryđể thiết lập kết nối và thời gian chờ đọc. Sau đó, nó được chuyển cho hàm tạo của RestTemplate.

@Configuration
public class AppConfig {

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {

        return builder
                .setConnectTimeout(Duration.ofMillis(3000))
                .setReadTimeout(Duration.ofMillis(3000))
                .build();
    }
}

Trong giải pháp thứ hai, chúng tôi sử dụng RestTemplateBuilder. Cũng lưu ý các tham số của hai phương thức: chúng lấy Duration. Các phương thức nạp chồng mất trực tiếp mili giây hiện không được dùng nữa.

Chỉnh sửa Đã kiểm tra với Spring Boot 2.1.0 và Java 11.


Bạn đang sử dụng phiên bản java và mùa xuân nào?
orirab,

2
Spring Boot 2.1.0 và Java 11. Để biết ví dụ làm việc, bạn có thể xem hướng dẫn của tôi: zetcode.com/springboot/resttemplate
Jan Bodnar

Tôi đề nghị thêm điều này vào câu trả lời
orirab 27/12/18

Xem github.com/spring-projects/spring-boot/blob/master/… . Nó đã được thêm vào Spring Boot 2.1.0.
Jan Bodnar

Cảm ơn bạn @JanBodnar, bạn hướng dẫn là duy nhất mà làm việc tốt trên 5.x Xuân Boot của tôi
Ângelo Polotto

15

Đây là một cách thực sự đơn giản để đặt thời gian chờ:

RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());

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

0

Tôi đã gặp trường hợp tương tự, nhưng cũng được yêu cầu đặt Proxy. Cách đơn giản nhất mà tôi có thể thấy để làm điều này là mở rộng SimpleClientHttpRequestFactoryđể dễ dàng thiết lập proxy (các proxy khác nhau cho non-prod vs prod). Điều này vẫn sẽ hoạt động ngay cả khi bạn không yêu cầu proxy. Sau đó, trong lớp mở rộng của tôi, tôi ghi đè openConnection(URL url, Proxy proxy)phương thức, sử dụng phương thức giống như nguồn , nhưng chỉ đặt thời gian chờ trước khi quay lại.

@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

Để mở rộng câu trả lời của benscabbia :

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. RestTemplate timeout với SimpleClientHttpRequestFactory Để ghi đè theo chương trình các thuộc tính timeout, chúng ta có thể tùy chỉnh lớp SimpleClientHttpRequestFactory như bên dưới.

Ghi đè thời gian chờ bằng 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. Thời gian chờ RestTemplate với HttpComponentsClientHttpRequestFactory SimpleClientHttpRequestFactory giúp thiết lập thời gian chờ nhưng nó rất hạn chế về chức năng và có thể không đủ trong các ứng dụng thời gian thực. Trong mã sản xuất, chúng ta có thể muốn sử dụng HttpComponentsClientHttpRequestFactory hỗ trợ thư viện HTTP Client cùng với resttemplate.

HTTPClient cung cấp các tính năng hữu ích khác như nhóm kết nối, quản lý kết nối nhàn rỗi, v.v.

Đọc thêm: Ví dụ cấu hình Spring RestTemplate + HttpClient

Ghi đè thời gian chờ bằng 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;
}

tham khảo: Ví dụ cấu hình thời gian chờ Spring RestTemplate

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.