I have a Spring Boot 2.3.1 project, in which I use WebClient to call a remote service.
The remote service is not very reliable and tends to return 500 errors, with and without response bodies. My goal is throw a custom exception that contains the response body (or a default message) so that I can log it, and here's my code :
webClient.get()
.uri(targetServiceUri)
.retrieve()
.onStatus(HttpStatus::is5xxServerError, clientResponse ->
clientResponse.bodyToMono(String.class)
.flatMap(error ->
Mono.error(new MyCustomServiceException(error))
)
)
.toEntity(String.class)
.block();
I have 2 tests using wiremock, the first one works :
@Test
void shouldThrowCustomExceptionWhenServiceReturns500ServerErrorWithNoBody() {
setStubForInValidCheckCall(HttpStatus.INTERNAL_SERVER_ERROR,"{'Error':'invalid request'}");
Throwable thrown =
catchThrowable(() -> myClient.performComplianceCheck(getCompany()));
assertThat(thrown)
.isInstanceOf(MyCustomServiceException.class)
.hasMessageContaining("{'Error':'invalid request'}");
}
private void setStubForInValidCheckCall(HttpStatus httpStatus, String body) {
var response= aResponse().withStatus(httpStatus.value());
if(body!=null){
response=response.withBody(body);
}
stubFor(
get(urlPathMatching("/targetCompliance"))
.willReturn(response));
}
However, the second test in which the response is 500 but there's no body (or if it's an empty string), fails with "java.lang.IllegalStateException: Only one connection receive subscriber allowed.
@Test
void shouldThrowCustomExceptionWhenServiceReturns500ServerErrorWithNoBody() {
setStubForInValidCheckCall(HttpStatus.INTERNAL_SERVER_ERROR,null);
Throwable thrown =
catchThrowable(() -> myClient.performComplianceCheck(getCompany()));
assertThat(thrown)
.isInstanceOf(MyCustomServiceException.class)
.hasMessageContaining("service returned status 500");
}
I am struggling to understand why this happens, and how to fix it..
is it "normal" ? or am I missing something obvious (is it a problem with my test ?) ?
I have found a workaround, but it doesn't feel "webFlux-y" at all, and I still don't understand why the Only one connection receive subscriber allowed
was happening :
try {
ResponseEntity<String> responseEntity =
webClient.get()
.uri(targetServiceUri)
.retrieve()
.toEntity(String.class)
.block();
}
catch (WebClientException e) {
if(e instanceof InternalServerError){
var internalServerError=(InternalServerError) e;
if(internalServerError.getStatusCode().is5xxServerError()){
var respBody=internalServerError.getResponseBodyAsString();
if(StringUtils.isEmpty(respBody)){
respBody=MY_STANDARD_MESSAGE +internalServerError.getRawStatusCode() ;
}
throw new MyCustomServiceException(respBody);
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.