Imagine I have the following the following 2 ClientHttpRequestInterceptor
s:
public class RequestLoggerInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
log.info("HTTP request: {}", httpRequest);
return clientHttpRequestExecution.execute(httpRequest, bytes);
}
}
public class ResponseLoggerInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
ClientHttpResponse response = clientHttpRequestExecution.execute(httpRequest, bytes);
log.info("HTTP response: {}", response);
return response
}
}
And I add them both to the same RestTemplate
:
ClientHttpRequestInterceptor requestLogger = new RequestLoggerInterceptor();
ClientHttpRequestInterceptor responseLoggerr = new ResponseLoggerInterceptor();
RestTemplate template = new RestTemplate();
template.setInterceptors(Arrays.asList(requestLogger, responseLogger));
What will be the behaviour when a request is executed using this RestTemplate
?
In both ClientHttpRequestInterceptor
s, the clientHttpRequestExecution.execute
method is called. Does this mean that the request is executed twice?
Interface ClientHttpRequestInterceptor This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference. Intercepts client-side HTTP requests.
Setting up the RestTemplate For instance, if we want our interceptor to function as a request/response logger, then we need to read it twice – the first time by the interceptor and the second time by the client. The default implementation allows us to read the response stream only once.
To work with interceptor, you need to create @Component class that supports it and it should implement the HandlerInterceptor interface. preHandle() method − This is used to perform operations before sending the request to the controller. This method should return true to return the response to the client.
REST Interceptor to Log Requests and Responses Below given RequestResponseLoggingInterceptor class implements ClientHttpRequestInterceptor interface. It implements intercept() method. In this method, we are logging the request and response details sent from RestTemplate .
From the documentation of ClientHttpRequestExecution
Represents the context of a client-side HTTP request execution. Used to invoke the next interceptor in the interceptor chain, or - if the calling interceptor is last - execute the request itself.
Hence the request will not execute twice. It will execute in following way,
clientHttpRequestExecution.execute
requestLogger.intercept
clientHttpRequestExecution.execute
responseLogger.intercept
clientHttpRequestExecution.execute
ClientHttpRequest.execute
For more details, read InterceptingClientHttpRequest InterceptingRequestExecution.execute
method.
RestTemplate
allows you to register multiple HTTP request interceptors by implementing the ClientHttpRequestInterceptor
(doc) interface.
Every such interceptor is a pass through for the HTTP request, eventually executing the request after passing through all the interceptors.
The signature of the method to be implemented in the interceptor is
ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException;
where the implementation of the execute method of ClientHttpRequestExecution
(doc) interface takes care of passing the request to the next interceptor or executing the request
if there are no more interceptors left to be intercepted by.
Since Spring 5.0.x, interceptors are sorted by Spring using AnnotationAwareOrderComparator
(doc)
and hence the sorting can be defined with @Order
or @Priority
too. So if you are in the said Spring version and you annotate the interceptors as below
@Order(1)
public class ResponseLoggerInterceptor implements ClientHttpRequestInterceptor {
...
}
@Order(2)
public class RequestLoggerInterceptor implements ClientHttpRequestInterceptor {
...
}
the request will first be intercepted by ResponseLoggerInterceptor
and then by RequestLoggerInterceptor
.
So in your case, the request will be intercepted by RequestLoggerInterceptor
and ResponseLoggerInterceptor
according to the sorted order and then finally executed. The request will be executed only once.
Note: RestTemplate will be deprecated in a future version and Spring suggests users to use WebClient instead of RestTemplate from version 5.0 onwards.
No, the request is only executed once at the end. When you set the interceptors in the rest template the underlying ClientHttpRequestFactory
is wrapped as InterceptingclientHttpRequestFactory
with interceptors.
When you made the request using rest template the request is read by interceptors followed by request execution and the response is processed by interceptors. That is all done using ClientHttpRequestExecution
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With