Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why my custom ClientHttpRequestInterceptor with empty response

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?

like image 755
maya16 Avatar asked Apr 25 '18 13:04

maya16


1 Answers

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;
}

}

like image 123
maya16 Avatar answered Sep 22 '22 16:09

maya16