2

我是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;
            });
}
4

1 回答 1

3

这两种解决方案都是丑陋和错误的。您几乎不应该在反应式管道的中间订阅。订阅者通常是调用客户端,而不是您自己的应用程序。

    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相同的方式使用。

于 2019-06-27T15:22:18.913 回答