Как правильно получить тело ответа от WebClient в случае ошибки? - PullRequest
0 голосов
/ 27 июня 2019

Я новичок в WebClient и реактивном программировании. Я хочу получить тело ответа на запрос. В случае ошибки http-код, заголовки и тело должны быть зарегистрированы, но тело все равно должно быть возвращено.

После долгих поисков и поисков я нашел два решения. Но оба выглядят сложными для меня. Есть ли более простое решение?

Оставаясь с Mono Я нашел это решение:

public Mono<String> log(ProtocolLine protocolLine) {
    return webClient.post()
            .uri("/log")
            .body(BodyInserters.fromObject(protocolLine))
            .exchange()
            .flatMap(clientResponse -> {
                Mono<String> stringMono = clientResponse.bodyToMono(String.class);
                CompletableFuture<String> stringCompleteFuture = new CompletableFuture<String>();
                Mono<String> bodyCompletedMono = Mono.fromFuture(stringCompleteFuture);
                if (clientResponse.statusCode().isError()) {
                    stringMono.subscribe(bodyString -> {
                        LOGGER.error("HttpStatusCode = {}", clientResponse.statusCode());
                        LOGGER.error("HttpHeaders = {}", clientResponse.headers().asHttpHeaders());
                        LOGGER.error("ResponseBody = {}", bodyString);
                        stringCompleteFuture.complete(bodyString);
                    });
                }

                return bodyCompletedMono;
            });
}

На основании Flux требуется меньше кода. Но я думаю, что я не должен использовать Flux, если я знаю, что будет только один результат.

public Flux<String> log(ProtocolLine protocolLine) {
    return webClient.post()
            .uri("/log")
            .body(BodyInserters.fromObject(protocolLine))
            .exchange()
            .flux()
            .flatMap(clientResponse -> {
                Flux<String> stringFlux = clientResponse.bodyToFlux(String.class).share();
                if (clientResponse.statusCode().isError()) {
                    stringFlux.subscribe(bodyString -> {
                        LOGGER.error("HttpStatusCode = {}", clientResponse.statusCode());
                        LOGGER.error("HttpHeaders = {}", clientResponse.headers().asHttpHeaders());
                        LOGGER.error("ResponseBody = {}", bodyString);
                    });
                }

                return stringFlux;
            });
}

1 Ответ

1 голос
/ 27 июня 2019

оба решения безобразны и ошибочны. Вы почти никогда не должны подписываться в середине реактивного конвейера. Абонентом обычно является вызывающий клиент, а не ваше собственное приложение.

    public Mono<String> log(ProtocolLine protocolLine) {
    return webClient.post()
            .uri("/log")
            .body(BodyInserters.fromObject(protocolLine))
            .exchange()
            .flatMap(clientResponse -> clientResponse.bodyToMono(String.class)
                .doOnSuccess(body -> {
                    if (clientResponse.statusCode().isError()) {
                        log.error("HttpStatusCode = {}", clientResponse.statusCode());
                        log.error("HttpHeaders = {}", clientResponse.headers().asHttpHeaders());
                        log.error("ResponseBody = {}", body);
                    }
            }));
}

Здесь вы можете увидеть способ мышления. Мы всегда берем наш clientResponse и отображаем его тело в строку. Затем мы doOnSuccess, когда это Mono используется абонентом (нашим вызывающим клиентом), и проверяем код состояния, если есть ошибка, и если это так, мы регистрируем.

Метод doOnSuccess возвращает void, поэтому он не «потребляет» моно или что-то еще, он просто запускает что-то, когда этот Mono говорит, что «что-то есть в себе», когда он «готов», так сказать.

Это можно использовать с Flux таким же образом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...