Spring RestTemplate หมดเวลา


125

ฉันต้องการตั้งค่าระยะหมดเวลาการเชื่อมต่อสำหรับบริการพักที่แอปพลิเคชันเว็บของฉันใช้ ฉันใช้ RestTemplate ของ Spring เพื่อพูดคุยกับบริการของฉัน ฉันได้ทำการค้นคว้าและพบและใช้ xml ด้านล่าง (ใน xml แอปพลิเคชันของฉัน) ซึ่งฉันเชื่อว่ามีไว้เพื่อตั้งค่าการหมดเวลา ฉันใช้ Spring 3.0

ฉันยังพบปัญหาเดียวกันที่นี่การกำหนดค่าการหมดเวลาสำหรับ Spring webservices ด้วย 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.ResourceAccessExcep ข้อผิดพลาด I / O: ไม่มีเส้นทางไปยังโฮสต์: เชื่อมต่อ; ข้อยกเว้นที่ซ้อนกันคือ java.net.NoRouteToHostException: ไม่มีเส้นทางไปยังโฮสต์: เชื่อมต่อ

URL ไม่ถูกต้องดังนั้น 404 จึงถูกส่งกลับโดย rest service: รอประมาณ 10 วินาทีและรายงานข้อยกเว้นต่อไปนี้:

org.springframework.web.client.HttpClientErrorException: ไม่พบ 404

ข้อกำหนดของฉันต้องการการหมดเวลาที่สั้นลงดังนั้นฉันจึงต้องสามารถเปลี่ยนแปลงสิ่งเหล่านี้ได้ มีความคิดเกี่ยวกับสิ่งที่ฉันทำผิดหรือไม่?

ขอบคุณมาก.

คำตอบ:


164

สำหรับ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มี setters สาธารณะconnectionRequestTimeout, connectTimeoutและreadTimeoutและ@ConfigurationPropertiesชุดพวกเขาสำหรับคุณ


สำหรับSpring 4.1 หรือ Spring 5 ที่ไม่มี Spring Boot ให้ใช้@ConfigurationแทนXML

@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

7
โปรดทราบว่าหลังจากการกำหนดค่านี้ RestTemplate จะใช้ไคลเอ็นต์ apache http (เพื่อตั้งค่าการหมดเวลา) เธรด maxPerRoute เริ่มต้นของพูลการเชื่อมต่อไคลเอ็นต์ของ Apache http คือ 5 และเธรดรวมสูงสุดคือ 10 (httpClient-4.5.2) เราจำเป็นต้องตั้งค่านี้ด้วยตัวเองในบางสถานการณ์ (เช่นเราต้องเชื่อมต่อกับโฮสต์จำนวนมากและต้องการการเชื่อมต่อเพิ่มเติม)
bluearrow

2
โปรดทราบconnectionRequestTimeoutแอตทริบิวต์ไม่สามารถใช้ได้ก่อน 4.1.4 RelEASE
Taoufik Mohdit

ฉันลองกำหนดค่าสำหรับ Spring Boot> = 1.4 บน Spring Boot> = 2.1.8 แล้ว แต่ก็ไม่สำเร็จ ฉันติดตามโพสต์นี้ ( zetcode.com/springboot/resttemplate ) เพื่อทำการกำหนดค่านั้น
Ângelo Polotto

@ ÂngeloPolottoลิงก์ที่คุณโพสต์ให้คำแนะนำเช่นเดียวกับโซลูชันนี้ บทความกล่าวว่า: "หรือเราสามารถใช้ RestTemplateBuilder เพื่อทำงานนี้ได้"
dustin.schultz

76

ในที่สุดฉันก็ทำงานนี้ได้

ฉันคิดว่าความจริงที่ว่าโครงการของเรามีโถ commons-httpclient สองเวอร์ชันที่แตกต่างกันไม่ได้ช่วยอะไร เมื่อฉันเรียงลำดับแล้วฉันพบว่าคุณสามารถทำได้สองอย่าง ...

ในโค้ดคุณสามารถใส่สิ่งต่อไปนี้:

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 วินาทีสำหรับการรับสาย ฯลฯ )
รหัสอัลซ่า

@ ซาร์โด. ที่ฉันใช้อินเทอร์เฟซ 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

41

คำถามนี้เป็นลิงก์แรกสำหรับการค้นหา Spring Boot ดังนั้นจึงเป็นการดีที่จะนำวิธีการแก้ปัญหาที่แนะนำในเอกสารอย่างเป็นทางการมาที่นี่ Spring Boot มีRestTemplateBuilder ของถั่วที่สะดวกสบายของตัวเอง:

@Bean
public RestTemplate restTemplate(
        RestTemplateBuilder restTemplateBuilder) {

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

การสร้างอินสแตนซ์ RestTemplate ด้วยตนเองเป็นแนวทางที่อาจเป็นปัญหาได้เนื่องจากถั่วที่กำหนดค่าอัตโนมัติอื่น ๆ จะไม่ถูกแทรกเข้าไปในอินสแตนซ์ที่สร้างขึ้นด้วยตนเอง


2
หมายเหตุสำหรับผู้มาใหม่ในฤดูใบไม้ผลิอย่างตัวฉัน: เพียงแค่ติดสิ่งนี้ไว้ใน @Configuration จะไม่ทำอะไรเลย วิธีนี้กำหนดให้คุณต้องฉีด RestTemplate นี้ในทุกที่ที่ใช้เป็นอาร์กิวเมนต์ของตัวสร้าง RestTemplateXhrTransport ซึ่งคุณจะเพิ่มลงในรายการการขนส่งของคุณที่คุณส่งผ่านไปยังถุงเท้าเจสไคลเอนต์
Key Lay

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


คุณใช้สปริงและจาวาเวอร์ชันใด
orirab

2
Spring Boot 2.1.0 และ Java 11 สำหรับตัวอย่างการใช้งานคุณสามารถดูบทช่วยสอนของฉัน: zetcode.com/springboot/resttemplate
Jan Bodnar

ฉันขอแนะนำให้เพิ่มสิ่งนี้ในคำตอบ
orirab

ดูgithub.com/spring-projects/spring-boot/blob/master/... มันถูกเพิ่มใน Spring Boot 2.1.0
ม.ค. Bodnar

ขอบคุณ @JanBodnar บทช่วยสอนของคุณเป็นสิ่งเดียวที่ทำงานได้ดีใน Spring Boot 5.x ของฉัน
Ângelo Polotto

15

นี่เป็นวิธีง่ายๆในการตั้งค่าระยะหมดเวลา:

RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());

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

0

ฉันมีสถานการณ์ที่คล้ายกัน แต่ก็จำเป็นต้องตั้งค่า Proxy ด้วย วิธีที่ง่ายที่สุดที่ฉันสามารถทำได้คือการขยายSimpleClientHttpRequestFactoryเพื่อความสะดวกในการตั้งค่าพร็อกซี (พร็อกซีที่แตกต่างกันสำหรับ non-prod vs prod) สิ่งนี้ยังคงใช้ได้แม้ว่าคุณจะไม่ต้องการพร็อกซีก็ตาม จากนั้นในคลาสเพิ่มเติมของฉันฉันจะแทนที่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;
}

0

หากต้องการขยายคำตอบของ 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 ด้วย 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 ช่วยในการตั้งค่าการหมดเวลา แต่มีข้อ จำกัด ในการทำงานและอาจไม่เพียงพอในแอปพลิเคชันแบบเรียลไทม์ ในโค้ดการผลิตเราอาจต้องการใช้ HttpComponentsClientHttpRequestFactory ซึ่งรองรับไลบรารีไคลเอ็นต์ HTTP พร้อมกับรีเฟรชเพลท

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.