在错误情况下从 WebClient 获取响应 body 的正确方法是什么?
What's the correct way to get the response body from a WebClient in an error case?
我是 WebClient
和响应式编程的新手。我想从请求中获得响应 body。如果出现错误,必须记录 http-code、headers 和 body,但仍应返回 body。
经过大量挖掘和谷歌搜索,我找到了两个解决方案。但对我来说,两者看起来都很复杂。有更简单的解决方案吗?
使用 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;
});
}
这两种解决方案都很丑陋且错误。你几乎不应该在反应管道的中间订阅。订阅者通常是调用客户端,而不是您自己的应用程序。
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
方法 returns void 所以它不会 "consume" 单声道或任何东西,它只是在这个 Mono
说它时触发一些东西 "has something in itself",当"done"这么说的时候。
这可以以相同的方式与 Flux
一起使用。
我是 WebClient
和响应式编程的新手。我想从请求中获得响应 body。如果出现错误,必须记录 http-code、headers 和 body,但仍应返回 body。
经过大量挖掘和谷歌搜索,我找到了两个解决方案。但对我来说,两者看起来都很复杂。有更简单的解决方案吗?
使用 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;
});
}
这两种解决方案都很丑陋且错误。你几乎不应该在反应管道的中间订阅。订阅者通常是调用客户端,而不是您自己的应用程序。
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
方法 returns void 所以它不会 "consume" 单声道或任何东西,它只是在这个 Mono
说它时触发一些东西 "has something in itself",当"done"这么说的时候。
这可以以相同的方式与 Flux
一起使用。