web-dev-qa-db-fra.com

Spring Webflux: Webclient: Récupération du corps en cas d'erreur

J'utilise le client Web printan Webflux, comme ceci:

WebClient.create()
            .post()
            .uri(url)
            .syncBody(body)
            .accept(MediaType.APPLICATION_JSON)
            .headers(headers)
            .exchange()
            .flatMap(clientResponse -> clientResponse.bodyToMono(tClass));

Cela fonctionne bien. Je souhaite maintenant gérer l’erreur du service Web que j’appelle (erreur interne Ex 500). Normalement, je voudrais ajouter un doOnError sur le "flux" et isu le Throwable pour tester le code d'état, 

Mais mon problème est que je veux obtenir le corps fourni par le service Web, car il me fournit un message que je voudrais utiliser.

Je cherche à faire le flatMap quoi qu'il arrive, et à tester moi-même le code d'état pour désérialiser ou non le corps.

5
adrien le roy

Notez que, au moment d'écrire cela, les erreurs 5xx n'entraînent plus d'exception de la couche Netty sous-jacente. Voir https://github.com/spring-projects/spring-framework/commit/b0ab84657b712aac59951420f4e9d696c3d84ba2

3
Arjen Poutsma

Je fais quelque chose comme ça:

Mono<ClientResponse> responseMono = requestSpec.exchange()
            .doOnNext(response -> {
                HttpStatus httpStatus = response.statusCode();
                if (httpStatus.is4xxClientError() || httpStatus.is5xxServerError()) {
                    throw new WebClientException(
                            "ClientResponse has erroneous status code: " + httpStatus.value() +
                                    " " + httpStatus.getReasonPhrase());
                }
            });

et alors:

responseMono.subscribe(v -> { }, ex -> processError(ex));
4
Artem Bilan

Nous avons enfin compris ce qui se passait: Par défaut, le httpclient (HttpClientRequest) de Netty est configuré pour échouer en cas d’erreur de serveur (réponse 5XX) et non d’erreur de client (4XX), raison pour laquelle il émettait toujours une exception .

Ce que nous avons fait, c’est d’étendre AbstractClientHttpRequest et ClientHttpConnector pour configurer le httpclient de la manière dont il veut et lorsque nous appelons le WebClient, nous utilisons notre ClientHttpConnector personnalisé:

 WebClient.builder().clientConnector(new CommonsReactorClientHttpConnector()).build();
3
adrien le roy

Tu pourrais aussi faire ça

return webClient.getWebClient()
 .post()
 .uri("/api/Card")
 .body(BodyInserters.fromObject(cardObject))
 .exchange()
 .flatMap(clientResponse -> {
     if (clientResponse.statusCode().is5xxServerError()) {
        clientResponse.body((clientHttpResponse, context) -> {
           return clientHttpResponse.getBody();
        });
     return clientResponse.bodyToMono(String.class);
   }
   else
     return clientResponse.bodyToMono(String.class);
});

Lisez cet article pour plus d'exemples link , je l'ai trouvé utile lorsque j'ai rencontré un problème similaire avec la gestion des erreurs

2
Mohale