Spring-boot Resttemplate response.body is null while interceptor clearly shows body
Asked Answered
G

5

7

With Spring-boot 1.5.10.RELEASE, I am getting response.body as null.

Here is how I am using RestTemplate

RestTemplate restTemplate = new RestTemplate();
    List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
    interceptors.add(new LoggingRequestInterceptor());
    restTemplate.setInterceptors(interceptors);

    String url = "http://someurl/Commands";

    MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
    params.add("cmd", "{\"operation\":\"getSomeDetails\"}}");

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
    HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);

    ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);

    System.out.println("This is always null: " + response.getBody());

While above program always prints null, following interceptor prints valid response body

public class LoggingRequestInterceptor implements ClientHttpRequestInterceptor {

final static Logger log = LoggerFactory.getLogger(LoggingRequestInterceptor.class);

@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
                                    final ClientHttpRequestExecution execution) throws IOException {
    traceRequest(request, body);
    ClientHttpResponse response = execution.execute(request, body);
    traceResponse(response);
    return response;
}


private void traceResponse(ClientHttpResponse response) throws IOException {
    StringBuilder inputStringBuilder = new StringBuilder();
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody(), "UTF-8"));
    String line = bufferedReader.readLine();
    while (line != null) {
        inputStringBuilder.append(line);
        inputStringBuilder.append('\n');
        line = bufferedReader.readLine();
    }
    log.debug("============================response begin==========================================");
    log.debug("Status code  : {}", response.getStatusCode());
    log.debug("Status text  : {}", response.getStatusText());
    log.debug("Headers      : {}", response.getHeaders());
    log.debug("Response body: {}", inputStringBuilder.toString());
    log.debug("=======================response end=================================================");
}

}

Granthem answered 2/3, 2018 at 4:32 Comment(0)
R
10

You're consuming the response body in traceResponse; that's your problem. Also, please update your question to be specific; "all latest" means nothing. What's latest today isn't so tomorrow.

Ridicule answered 2/3, 2018 at 5:9 Comment(1)
Thanks a lot Abhijit!Granthem
A
22

Although the accepted answer has the reason, I believe the solution is also necessary.

Spring has a BufferingClientHttpRequestFactory that acts as a wrapper to Rest Template's default SimpleClientHttpRequestFactory. It can be passed to a Rest Template during creation. This forces the Rest Template to make interceptors use a copy of the response rather than destroying it.

ClientHttpRequestFactory factory = new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory());

RestTemplate restTemplate = new RestTemplate(factory);

Source : http://objectpartners.com/2018/03/01/log-your-resttemplate-request-and-response-without-destroying-the-body/

Appressed answered 9/11, 2018 at 7:31 Comment(0)
R
10

You're consuming the response body in traceResponse; that's your problem. Also, please update your question to be specific; "all latest" means nothing. What's latest today isn't so tomorrow.

Ridicule answered 2/3, 2018 at 5:9 Comment(1)
Thanks a lot Abhijit!Granthem
L
1

Below code will resolve issue.

@Bean public RestTemplate restTemplate() {
final RestTemplate restTempate = new RestTemplate(new BufferingClientHttpRequestFactory(new
                  SimpleClientHttpRequestFactory()));
final List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
interceptors.add(new LogHttpInterceptor());
restTempate.setInterceptors(interceptors);
return restTemplate;}

While log interceptor will be like below

public class LogHttpInterceptor implements ClientHttpRequestInterceptor {

final static Logger log = LoggerFactory.getLogger(LogHttpInterceptor.class);

@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
    traceRequest(request, body);
    ClientHttpResponse response = execution.execute(request, body);
    traceResponse(response);
    return response;
}

private void traceRequest(HttpRequest request, byte[] body) throws IOException {
    log.info("===========================================================================request begin");
    log.debug("URI         : {}", request.getURI());
    log.debug("Method      : {}", request.getMethod());
    log.debug("Headers     : {}", request.getHeaders() );
    log.debug("Request body: {}", new String(body, "UTF-8"));
    log.info("=============================================================================request end");
}

private void traceResponse(ClientHttpResponse response) throws IOException {
    StringBuilder inputStringBuilder = new StringBuilder();
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody(), "UTF-8"));
    String line = bufferedReader.readLine();
    while (line != null) {
        inputStringBuilder.append(line);
        inputStringBuilder.append('\n');
        line = bufferedReader.readLine();
    }
    log.info("==========================================================================response begin");
    log.debug("Status code  : {}", response.getStatusCode());
    log.debug("Status text  : {}", response.getStatusText());
    log.debug("Headers      : {}", response.getHeaders());
    log.debug("Response body: {}", inputStringBuilder.toString());
    log.info("===========================================================================response end");
}

Let me know if doesn't work

Lytton answered 1/4, 2019 at 9:46 Comment(0)
H
1

After some time of searching I tried to use HttpComponentsClientHttpRequestFactory() instead of SimpleClientHttpRequestFactory()

ClientHttpRequestFactory factory = new BufferingClientHttpRequestFactory(new HttpComponentsClientHttpRequestFactory());

That solved the issue for me.

Haik answered 13/1, 2022 at 10:32 Comment(0)
T
0

Create your RestTemplate like this

@Bean
    public RestTemplate interceptedRestTemplate() {
        RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(
                new SimpleClientHttpRequestFactory()
        ));
        restTemplate.setInterceptors(List.of(<i>your interceptor</i>));
        return restTemplate;
    }

worked for me.

Tritheism answered 11/6, 2020 at 18:30 Comment(2)
I don't know what do you mean by that question, I mean a person asks a question about his/her problem and I'm giving the specific solution that has worked for me, what is so special about it for you?Tritheism
I mean that you didn't explain why did it work, just that it worked. "Give a man to fish..." etc.Ridicule

© 2022 - 2024 — McMap. All rights reserved.