160 votes

Spring RestTemplate timeout

Je voudrais définir les délais de connexion pour un service de repos utilisé par mon application Web. J'utilise le RestTemplate de Spring pour communiquer avec mon service. J'ai fait quelques recherches et j'ai trouvé et utilisé le xml ci-dessous (dans le xml de mon application) qui, je pense, est destiné à définir le timeout. J'utilise Spring 3.0.

J'ai également vu le même problème ici Configuration du délai d'attente pour les webservices de Spring avec RestTemplate mais les solutions ne semblent pas si nettoyer Je préfère définir les valeurs des délais d'attente via la configuration de 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>

Il semble que quel que soit le réglage du délai de lecture, j'obtienne le résultat suivant :

Le câble réseau est déconnecté : Il attend environ 20 secondes et signale l'exception suivante :

org.springframework.web.client.ResourceAccessExcep tion : Erreur d'E/S : No route to host : connect ; l'exception imbriquée est java.net.NoRouteToHostException : Pas de route vers l'hôte : connect

Url incorrecte donc 404 renvoyé par le service de repos : Il attend environ 10 secondes et signale l'exception suivante :

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

Comme mes besoins exigent des délais plus courts, je dois pouvoir les modifier. Avez-vous une idée de ce que je fais de mal ?

Merci beaucoup.

212voto

dustin.schultz Points 165

Pour Spring Boot >= 1.4

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

Pour 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());
    }
}

alors dans votre application.properties

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

Cela fonctionne parce que HttpComponentsClientHttpRequestFactory a des régleurs publics connectionRequestTimeout , connectTimeout y readTimeout y @ConfigurationProperties les définit pour vous.


Pour Spring 4.1 ou Spring 5 sans Spring Boot en utilisant @Configuration au lieu de XML

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

        return new RestTemplate(httpRequestFactory);
    }
}

79voto

sardo Points 2541

J'ai finalement réussi à le faire fonctionner.

Je pense que le fait que notre projet avait deux versions différentes du jar commons-httpclient n'a pas aidé. Une fois que j'ai résolu ce problème, j'ai découvert que vous pouvez faire deux choses...

Dans le code, vous pouvez mettre ce qui suit :

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

La première fois que ce code sera appelé, il fixera le délai d'attente pour la fonction HttpComponentsClientHttpRequestFactory utilisée par le RestTemplate . Par conséquent, tous les appels ultérieurs effectués par RestTemplate utilisera les paramètres de délai d'attente définis ci-dessus.

Ou la meilleure option est de faire ceci :

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

Où j'utilise le RestOperations dans mon code et obtenir les valeurs du délai d'attente à partir d'un fichier de propriétés.

59voto

heldev Points 676

Cette question est le premier lien pour une recherche sur Spring Boot, donc, ce serait bien de mettre ici le solution recommandée dans la documentation officielle . Spring Boot possède son propre bean de commodité RestTemplateBuilder :

@Bean
public RestTemplate restTemplate(
        RestTemplateBuilder restTemplateBuilder) {

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

La création manuelle d'instances RestTemplate est une approche potentiellement gênante car les autres beans auto-configurés ne sont pas injectés dans les instances créées manuellement.

29voto

Jan Bodnar Points 667

Voici mes deux cents. Rien de nouveau, mais quelques explications, des améliorations et du code plus récent.

Par défaut, RestTemplate a un délai d'attente infini. Il existe deux types de délais d'attente : le délai de connexion et le délai de lecture. Par exemple, j'ai pu me connecter au serveur mais je n'ai pas pu lire les données. L'application était suspendue et vous n'aviez aucune idée de ce qui se passait.

Je vais utiliser les annotations, qui sont aujourd'hui préférées au XML.

@Configuration
public class AppConfig {

    @Bean
    public RestTemplate restTemplate() {

        var factory = new SimpleClientHttpRequestFactory();

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

        return new RestTemplate(factory);
    }
}

Ici, nous utilisons SimpleClientHttpRequestFactory pour régler la connexion et les délais de lecture. Il est ensuite passé au constructeur de RestTemplate .

@Configuration
public class AppConfig {

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {

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

Dans la deuxième solution, nous utilisons le RestTemplateBuilder . Remarquez également les paramètres des deux méthodes : elles prennent Duration . Les méthodes surchargées qui prennent directement des millisecondes sont maintenant dépréciées.

Modifier Testé avec Spring Boot 2.1.0 et Java 11.

17voto

benscabbia Points 8725

Voici une méthode très simple pour définir le délai d'attente :

RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X