6
votes

I have done the following for my custom logging interceptor

public class HttpLoggingInterceptor implements ClientHttpRequestInterceptor {
    private final static Logger log = LoggerFactory.getLogger(HttpLoggingInterceptor.class);

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

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

    }

    private void logResponse(ClientHttpResponse response) throws IOException {
        log.info("Response Status code : {}, Status text : {}, Headers : {}, Response body: {}", response.getStatusCode(), response.getStatusText(), response.getHeaders(), StreamUtils.copyToString(response.getBody(), Charset.defaultCharset()));
    }
}

And I am setting the intercepter to the restTemplate

   @Autowired
    public RestTemplate restTemplate;

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        List<ClientHttpRequestInterceptor> clientHttpRequestInterceptors = new ArrayList<>();
        clientHttpRequestInterceptors.add(new HttpLoggingInterceptor());
//        clientHttpRequestInterceptors.addAll(restTemplate.getInterceptors());
        restTemplate.setInterceptors(clientHttpRequestInterceptors);
//        restTemplate.setInterceptors(Collections.singletonList(new HttpLoggingInterceptor()));
}

The logger is printing the response properly to the console, But at the end the response is returned as empty to the caller. I am not able to debug and figure it out.

I have figured it out that the StreamUtils.copyToString(response.getBody(), Charset.defaultCharset()) is reading the input stream once and it is no more holding the response body in it (which is empty now)

Anyone else also facing the same issue and has any idea of duplicating the InputStream without reading it from the original InputStream?

1
InputStream can be consumed only once. So there is no workaround except storing InputStream data into intermediate variable and creating new InputStream from that data (it actually is "duplicating")Nikolai Shevchenko
yes, you are right, There is only way you can read the HttpInputStream multiple times by using ew RestTemplate(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory())) I have posted the answer belowmaya16

1 Answers

5
votes

Since the input stream can be consumed only once and there is no reset() or mark(***) function available for sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.

There is only one way to read the response multiple time by creating the restTemplate in the following way.

@Bean
public RestTemplate getfxoWsClientRestTemplate(){
    RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
    restTemplate.setInterceptors(Collections.singletonList(new HttpLoggingInterceptor()));
    return  restTemplate;
}

And the LoggingIntercepter can be written like this

public class HttpLoggingInterceptor implements ClientHttpRequestInterceptor {

    private final static Logger logger = LoggerFactory.getLogger(HttpLoggingInterceptor.class);

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
    logger.info("request method: {}, request URI: {}, request headers: {}, request body: {}",
            request.getMethod(), request.getURI(), request.getHeaders(), new String(body, Charset.forName("UTF-8")));

    ClientHttpResponse response = execution.execute(request, body);

    logger.info("response status code: {}, response headers: {}, response body: {}",
            response.getStatusCode(), response.getHeaders(), new String(ByteStreams.toByteArray(response.getBody()), Charset.forName("UTF-8")));

    return response;
}

}