web-dev-qa-db-ja.com

Spring RestTemplateのタイムアウト

Webアプリケーションで使用されるRESTサービスの接続タイムアウトを設定したいと思います。 SpringのRestTemplateを使用してサービスと通信しています。私はいくつかの調査を行い、タイムアウトを設定することを意図していると信じている以下のxmlを見つけました(私のアプリケーションxmlで)。 Spring 3.0を使用しています。

ここでも同じ問題が見られました RestTemplateを使用したSpring Webサービスのタイムアウト構成 しかし、ソリューションは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.ResourceAccessException:I/Oエラー:ホストへのルートがありません:接続;ネストされた例外はJava.net.NoRouteToHostException:ホストへのルートなし:接続

URLが正しくないため、レストサービスから404が返されました:約10秒待機し、次の例外を報告します。

org.springframework.web.client.HttpClientErrorException:404 Not Found

要件により短いタイムアウトが必要なので、これらを変更できる必要があります。私が間違っていることに関するアイデアはありますか?

どうもありがとう。

97
sardo

私はついにこれを機能させました。

私たちのプロジェクトにはcommons-httpclient jarの2つの異なるバージョンがあったという事実は役に立たなかったと思います。それを整理したら、次の2つのことができることがわかりました...

コードには、次のものを含めることができます。

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インターフェイスを使用し、プロパティファイルからタイムアウト値を取得します。

67
sardo

Spring Boot> = 1.4の場合

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

Spring Boot <= 1.の場合

@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にパブリックセッターconnectionRequestTimeoutconnectTimeout、およびreadTimeoutおよび@ConfigurationPropertiesが設定されているために機能します。


Spring 4.1またはSpring BootなしのSpring 5XMLの代わりに@Configurationを使用

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

        return new RestTemplate(httpRequestFactory);
    }
}
132
dustin.schultz

この質問は、Spring Bootの検索の最初のリンクです。したがって、ここに 公式ドキュメントで推奨されている解決策 を入れるとよいでしょう。 Spring Bootには独自の便利なBeanがあります RestTemplateBuilder

@Bean
public RestTemplate restTemplate(
        RestTemplateBuilder restTemplateBuilder) {

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

RestTemplateインスタンスの手動作成は、他の自動構成されたBeanが手動で作成されたインスタンスに挿入されないため、面倒なアプローチになる可能性があります。

19
heldev

タイムアウトを設定する非常に簡単な方法を次に示します。

RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());

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

これが私の2セントです。新しいものはありませんが、いくつかの説明、改善、新しいコードがあります。

デフォルトでは、RestTemplateのタイムアウトは無限です。タイムアウトには、接続タイムアウトと読み取りタイムアウトの2種類があります。たとえば、サーバーに接続できましたが、データを読み取ることができませんでした。アプリケーションがハングしていて、何が起こっているのかわからない。

アノテーションを使用します。アノテーションは最近では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();
    }
}

2番目のソリューションでは、RestTemplateBuilderを使用します。また、2つのメソッドのパラメーターに注意してください:それらはDurationを取ります。直接ミリ秒かかるオーバーロードメソッドは廃止されました。

編集 Spring Boot 2.1.0およびJava 11.でテスト済み.

8
Jan Bodnar

同様のシナリオがありましたが、プロキシを設定する必要もありました。これを行うための最も簡単な方法は、プロキシの設定を容易にするために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;
}
0
Ryan D