Я новичок в реактивном программировании, и у меня есть служба REST, которая принимает запрос, а затем вызывает другой API с помощью WebFlux WebClient. Когда API отвечает ответом 4xx или 5xx, я хочу зарегистрировать тело ответа в своей службе, а затем передать ответ вызывающей стороне. Я нашел несколько способов ведения журнала ответа, но они обычно возвращают вызывающему объекту Mono.error, а я не хочу этого делать. У меня это почти работает, но когда я делаю запрос в свою службу, пока я возвращаю код 4xx, который вернул API, мой клиент просто зависает, ожидая тела ответа, и служба, похоже, никогда не завершает обработку потока . Я использую Spring Boot версии 2.2.4.RELEASE.
Вот что у меня есть:
Контроллер:
@PostMapping(path = "create-order")
public Mono<ResponseEntity<OrderResponse>> createOrder(@Valid @RequestBody CreateOrderRequest createOrderRequest) {
return orderService.createOrder(createOrderRequest);
}
Сервис:
public Mono<ResponseEntity<OrderResponse>> createOrder(CreateOrderRequest createOrderRequest) {
return this.webClient
.mutate()
.filter(OrderService.errorHandlingFilter(ORDERS_URI, createOrderRequest))
.build()
.post()
.uri(ORDERS_URI)
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(createOrderRequest)
.exchange()
.flatMap(response -> response.toEntity(OrderResponse.class));
}
public static ExchangeFilterFunction errorHandlingFilter(String uri, CreateOrderRequest request) {
return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> {
if (clientResponse.statusCode() != null && (clientResponse.statusCode().is5xxServerError() || clientResponse.statusCode().is4xxClientError())) {
return clientResponse.bodyToMono(String.class)
.flatMap(errorBody -> OrderService.logResponseError(clientResponse, uri, request, errorBody));
} else {
return Mono.just(clientResponse);
}
});
}
static Mono<ClientResponse> logResponseError(ClientResponse response, String attemptedUri, CreateOrderRequest orderRequest, String responseBody) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
try {
log.error("Response code {} received when attempting to hit {}, request:{}, response:{}",
response.rawStatusCode(), attemptedUri, objectMapper.writeValueAsString(orderRequest),
responseBody);
} catch (JsonProcessingException e) {
log.error("Error attempting to serialize request object when reporting on error for request to {}, with code:{} and response:{}",
attemptedUri, response.rawStatusCode(), responseBody);
}
return Mono.just(response);
}
Как видите, я просто пытаюсь вернуть Mono исходного ответа из метода logResponseError. Для своего тестирования я отправляю тело с плохим элементом, что приводит к ответу 422 Unprocessable Entity от конечной точки ORDERS_URI в API, который я вызываю. Но по какой-то причине, хотя клиент, который вызвал конечную точку порядка создания, получает 422, он никогда не получает тело. Если я изменю значение return в методе logResponseError на
return Mono.error(new Exception("Some error"));
, я получаю 500 на клиенте, и запрос завершается. Если кто-нибудь знает, почему он не завершается, когда я пытаюсь отправить ответ, я хотел бы знать, что я делаю не так.