0

We are moving our code from RestTemplate to WebClient to achieve non-blocking call and we are almost done it. But, after moving our code to WebClient we facing issue as when client makes call to our API, we are responding with blank response. Although, our backend client has response.

I tried, ofResponseProcessor, but this isn't executing it seems (as logs inside method is not getting printed)

Here is my code :

Mono<ClientResponse> clientResponse = WebClient.builder()
                .clientConnector(new ReactorClientHttpConnector(clientOptions))
                .filter(processResponse(httpResponse)) <-- passing HttpServletResponse
                .baseUrl("https://xxxxx.xxxx/")
                .build()
                .get()
                .uri("/getresult")
                .exchange();
logger.info("======Thread Completed=====");

Now, our processResponse will write response from ClientResponse to HttpServletResponse

public ExchangeFilterFunction processResponse(HttpServletResponse resp) {
        return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> {
             logger.info("======Writing Response=====");
             writeResponse(clientResponse,resp); //writing response to servletresponse
             return Mono.just(clientResponse);
        });
    }

I don't see ======Writing Response===== in my console log.

I also tried using subscribe on ClientResponse, but I'm still getting blank response until I put Thread.sleep.

Can anyone help me about what am I missing here ?

====Update=====

private void writeResponse(ClientResponse clientResponse, HttpServletResponse resp){

clientResponse.bodyToMono(String.class)
   .subscribe(consumer -> {
       ....
       ....
       IOUtils.copy(new ByteArrayInputStream(consumer.getBytes()),resp.getOutputStream());
    }
   ...
  );
}
cool_ravi
  • 165
  • 1
  • 9

1 Answers1

1

Because you are using non-blocking calls the thread that executes the API call (and the subscribe block) is different from the main thread, so the main thread will continue executing the rest of code and returns the response although the other thread is not finished yet.

So you have two options make your API reactive so you can return the Mono object directly and is the client of the API the one that subscribes to it, or if you want synchronous (non-reactive) API you have to call the block method of the Mono object to allow the main thread to obtain the result of the external call

JArgente
  • 2,239
  • 1
  • 9
  • 11
  • can you share sample code for first approach and will try. I mean, what should I change in my code for approach ? – cool_ravi Jun 29 '21 at 07:45
  • the problem that I see with the first approach in your case is that you are writing directly in the httpservletresponse object, you are not returning a json or other object that is consumed by other frontend or backend application. Is this a server side render application that outputs the HTML code directly? – JArgente Jun 29 '21 at 07:48
  • Yes, this is server side rendering, and output/response consume by client. So, basically, we are fetching data from other service and rendering the response and then writing to servletresponse for our client. – cool_ravi Jun 29 '21 at 08:02
  • 1
    then in this case you should block the webclient response to obtain the response in the main thread and return it. – JArgente Jun 29 '21 at 08:08
  • are you saying, there is no other way other than block, I was reading about `DeferredResult` and `ListenableFuture`, not sure if that will help, any idea ? – cool_ravi Jun 29 '21 at 08:15
  • 1
    The problem here is that your API is synchronous so you have no other way to wait until the weblclient response finished in order to return the result to your client. You can take advantage of non blocking feature if you need to make other external calls and make them is parallel or make any transform in the mono using the operators like map, filter, flatmap etc.. but in the end you have to call block to get the result in the main thread – JArgente Jun 29 '21 at 08:20
  • can we implement like callback, we are just trying to solve blocking I/O. So, if some how we can achieve by making changes in our code ? – cool_ravi Jun 29 '21 at 08:26
  • if you need to get the response of the webclient request before return the response to your client you have to "block" until you get the response, there is no other way. Things can be different if your client could subscribe to your service and this way it will receive the answer when it is ready, but to do this you have to return a Flux or Mono in your controller and when the client makes the call to that endpoint it will be subscribed – JArgente Jun 29 '21 at 08:33
  • we added `block` to our code.. but still having same issue intermittently, do you suggest any thing ? – cool_ravi Jun 29 '21 at 12:03