Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
684 views
in Technique[技术] by (71.8m points)

java - Spring WebClient - how to access response body in case of HTTP errors (4xx, 5xx)?

I want to re-throw my exception from my "Database" REST API to my "Backend" REST API but I lose the original exception's message.

This is what i get from my "Database" REST API via Postman:

{
    "timestamp": "2020-03-18T15:19:14.273+0000",
    "status": 400,
    "error": "Bad Request",
    "message": "I'm DatabaseException (0)",
    "path": "/database/api/vehicle/test/0"
}

This part is ok.

This is what i get from my "Backend" REST API via Postman:

{
    "timestamp": "2020-03-18T15:22:12.801+0000",
    "status": 400,
    "error": "Bad Request",
    "message": "400 BAD_REQUEST ""; nested exception is org.springframework.web.reactive.function.client.WebClientResponseException$BadRequest: 400 Bad Request from GET http://localhost:8090/database/api/vehicle/test/0",
    "path": "/backend/api/vehicle/test/0"
}

As you can see the original "message" field is lost.

I use:

  • Spring boot 2.2.5.RELEASE
  • spring-boot-starter-web
  • spring-boot-starter-webflux

Backend and Database start with Tomcat (web and webflux in the same application).

This is Backend:

    @GetMapping(path = "/test/{id}")
    public Mono<Integer> test(@PathVariable String id) {
        return vehicleService.test(id);
    }

With vehicleService.test:

    public Mono<Integer> test(String id) {
        return WebClient
            .create("http://localhost:8090/database/api")
            .get()
            .uri("/vehicle/test/{id}", id)
            .accept(MediaType.APPLICATION_JSON)
            .retrieve()
            .bodyToMono(Integer.class);
    }

This is Database:

    @GetMapping(path = "/test/{id}")
    public Mono<Integer> test(@PathVariable String id) throws Exception {

        if (id.equals("0")) {
            throw new DatabaseException("I'm DatabaseException (0)");
        }

        return Mono.just(Integer.valueOf(2));
    }

I also tried with return Mono.error(new DatabaseException("I'm DatabaseException (0)"));

And DatabaseException:

public class DatabaseException extends ResponseStatusException {

    private static final long serialVersionUID = 1L;

    public DatabaseException(String message) {
        super(HttpStatus.BAD_REQUEST, message);

    }
}

It seems my Backend transforms the response and can't find any answer on internet.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Instead of retrieve of WebClient, you could use exchange which lets you handle the error and propagate a custom exception with a message retrieved from the service response.

private void execute()
{
    WebClient webClient = WebClient.create();

    webClient.get()
             .uri("http://localhost:8089")
             .exchangeToMono(this::handleResponse)
             .doOnNext(System.out::println)
             .block();  // not required, just for testing purposes
}

private Mono<Response> handleResponse(ClientResponse clientResponse)
{
    if (clientResponse.statusCode().isError())
    {
        return clientResponse.bodyToMono(Response.class)
                             .flatMap(response -> Mono.error(new RuntimeException(response.message)));
    }

    return clientResponse.bodyToMono(Response.class);
}

private static class Response
{
    private String message;

    public Response()
    {
    }

    public String getMessage()
    {
        return message;
    }

    public void setMessage(String message)
    {
        this.message = message;
    }

    @Override
    public String toString()
    {
        return "Response{" +
                "message='" + message + ''' +
                '}';
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

56.9k users

...