我试图用一个网络客户端来替换现有的客户机代码。因此,大多数调用都需要阻塞,这样应用程序的主要部分就不需要更改。当谈到错误处理时,这会带来一些问题。必须涵盖以下几种情况:
List
为了产生正确的错误(异常),需要考虑错误响应。到目前为止,我还无法掌握错误主体。
我正在使用这个
RestController
方法来产生错误响应:
@GetMapping("/error/404")
@ResponseStatus(HttpStatus.NOT_FOUND)
public ResponseEntity error404() {
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse());
}
使用此响应对象:
public class ErrorResponse {
private String message = "Error message";
public String getMessage() {
return message;
}
}
网络客户端定义如下:
WebClient.builder()
.baseUrl("http://localhost:8081")
.clientConnector(connector)
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
连接器类型为CloseableHttpAsyncClient(Apache Http客户端5)。
从我的测试应用程序中,我这样调用:
public String get(int httpStatus) {
try {
return webClient.get()
.uri("/error/" + httpStatus)
.retrieve()
.onStatus(HttpStatus::isError, clientResponse -> {
clientResponse.bodyToMono(String.class).flatMap(responseBody -> {
log.error("Body from within flatMap within onStatus: {}", responseBody);
return Mono.just(responseBody);
});
return Mono.error(new RuntimeException("Resolved!"));
})
.bodyToMono(String.class)
.flatMap(clientResponse -> {
log.warn("Body from within flatMap: {}", clientResponse);
return Mono.just(clientResponse);
})
.block();
} catch (Exception ex) {
log.error("Caught Error: ", ex);
return ex.getMessage();
}
}
我得到的是来自
onstatus
返回的RuntimeException
,当然还有最终捕获的异常。我缺少来自onstatus
内的body ToMono
的处理。我的怀疑是,由于阻塞性质,这没有执行,因为响应体是在onstatus
之后处理body ToMono
的。在注释掉onstatus
时,我希望我们将警告记录在平图
中,这也不会发生。
最后,我想将错误处理定义为一个过滤器,这样代码就不需要在每次调用时重复,但我需要获得错误响应主体,这样可以用正确的数据填充异常。
如何在同步WebClient调用中检索错误响应?
这个问题类似于Spring Webflux:Webclient:Get body on error,它没有公认的答案,并且一些建议的方法使用的方法没有被弃用。
以下是一种处理错误响应的方法:
webClient.get()
.uri("/error/" + httpStatus)
.retrieve()
.onStatus(HttpStatus::isError, clientResponse ->
clientResponse.bodyToMono(ErrorResponse.class)
.flatMap(error ->
Mono.error(new RuntimeException(error.getMessage()))
)
)
.bodyToMono(Response.class)
你真的不需要试试catch。如果block
,如果是非错误响应,上述代码将返回Response
,如果是错误响应,则抛出带有自定义消息的异常。
更新
下面是使用WireMock的完整测试
class WebClientErrorHandlingTest {
private WireMockServer wireMockServer;
@BeforeEach
void init() {
wireMockServer = new WireMockServer(wireMockConfig().dynamicPort());
wireMockServer.start();
WireMock.configureFor(wireMockServer.port());
}
@Test
void test() {
stubFor(post("/test")
.willReturn(aResponse()
.withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.withStatus(400)
.withBody("{\"message\":\"Request error\",\"errorCode\":\"10000\"}")
)
);
WebClient webClient = WebClient.create("http://localhost:" + wireMockServer.port());
Mono<Response> request = webClient.post()
.uri("/test")
.retrieve()
.onStatus(HttpStatus::isError, clientResponse ->
clientResponse.bodyToMono(ErrorResponse.class)
.flatMap(error ->
Mono.error(new RuntimeException(error.getMessage() + ": " + error.getErrorCode()))
)
)
.bodyToMono(Response.class);
RuntimeException ex = assertThrows(RuntimeException.class, () -> request.block());
assertEquals("Request error: 10000", ex.getMessage());
}
@Data
private static class ErrorResponse {
private String message;
private int errorCode;
}
@Data
private static class Response {
private String result;
}
}
我正在使用Spring Data Elasticsearch来获取一些聚合,并尝试使用ReactiveElasticsearchClient。我从Elasticsearch得到一个500错误,但我不知道如何获得响应的主体,以便调试请求的错误。以下是我目前掌握的情况: 为组织启用跟踪日志记录。springframework。数据elasticsearch。客户WIRE,将记录请求正文,但响应的日志行
首先,如果这是一个很长的代码段,我很抱歉,但是,我想做一个模态窗口,它将你在我的用户表单中写的东西写下来,并要求你确认它。我目前正在学习Javascript,我不允许使用innerHTML,我必须动态地编写“名字”等(名字的文本),不允许只在弹出窗口内写它。我已经让大多数东西工作,但“名字”“名字”等显示为“未定义”,或者(正如你可以看到的,我在这种情况下只用名字尝试的事情)显示为“空”。 希望有
我想将我的异常从我的“数据库”REST API重新抛出到我的“后端”REST API,但我丢失了原始异常的消息。 这是我通过Postman从我的“数据库”REST API中得到的: 这部分没问题。 这是我通过Postman从我的“后端”REST API得到的: 如您所见,原来的“message”字段丢失了。 我使用: Spring boot 2.2.5.发布 spring-boot-starter
在我的响应中,有一个,没有任何。那么,我如何获取该响应呢? 这是我的JSON代码-
问题内容: 我正在发出HTTP请求并侦听“数据”: 问题在于响应是分块的,因此“数据”只是发送回的一部分内容。 我如何将全身退回? 问题答案:
我有一个rest web服务。如果抛出任何异常,web服务将返回http 500错误。但我不想发送这个带有异常堆栈跟踪的错误响应。我只想发送错误代码和错误消息。我没有做到这一点。我怎么能这么做? 我已经尝试过@ControllerAdvice和@ExceptionHandler注释,但我做不到。当我使用@ResponseStatus注释时,总是发送静态“reason”值。如何设置此值?谢谢你的帮助