9

I'm currently trying to incorporate a HandlerInterceptorAdapter but it's not getting registered and comparing it to other answers is tough because everyone is using something different. And I'm aware WebMvcConfigureAdapter is deprecated, some versioning is beyond my control for the scope of the project, see usage specs below.

Can someone please provide some guidance on incorporating interceptors with a RestTemplate (that's not ClientHttpRequestInterceptor).

Main:

@SpringBootApplication @EnableRetry public class Application extends SpringBootServletInitializer { public static void main(String[] args) { ApplicationContext ctx = SpringApplication.run(Application.class, args); } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder applicationBuilder) { return applicationBuilder.sources(Application.class); } @Bean private RestTemplate restTemplate(){ Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("redacted", 8080)); SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory(); simpleClientHttpRequestFactory.setProxy(proxy); simpleClientHttpRequestFactory.setOutputStreaming(false); RestTemplate template = new RestTemplate(); template.setErrorHandler(new MyResponseErrorHandler()); return template; } } 

Interceptor : com.example.foo.config.request.interceptor

@Component public class MyInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("INTERCEPTED"); return super.preHandle(request, response, handler); } } 

InterceptorConfig : com.example.foo.config.request.interceptor

@Configuration public class InterceptorConfig extends WebMvcConfigurerAdapter { @Bean MyInterceptor myInterceptor() { return new MyInterceptor(); } @Override public void addInterceptors(InterceptorRegistry registry) { super.addInterceptors(registry); System.out.println("Adding interceptor"); registry.addInterceptor(myInterceptor()); } } 

"Adding interceptor" does get logged so I know the configs are being scanned. I just can't get any interceptor logic to log.

Using:

  • Spring Boot v1.5.15
  • Spring Version: 4.3.18.RELEASE
2
  • I think the problem is related to you initiating the RestTemplate. Please use it with autowired @Autowired private RestTemplate restTemplate;. Even the interceptor should be Autowired. I would suggest see this project as an example github.com/Asatnin/SpringMicroservices/blob/… Commented Aug 18, 2019 at 5:59
  • Thanks @TarunLalwani I tried AutoWiring before asking the question and it didn't matter, I AutoWire the Rest Template in my Service as well. You're example looks very similar to my set up but your interceptor uses the rest exchange method so maybe that is the key. I will try and update you Commented Aug 18, 2019 at 19:28

4 Answers 4

6
+250

RestTemplate expects ClientHttpRequestInterceptor

setInterceptors(List<ClientHttpRequestInterceptor> interceptors) 

Set the request interceptors that this accessor should use.

You can use Servlet Filter to "intercept" requests/response,

@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; 

implement this with a servlet filter. No Spring involved here at all

But you will have to change RestTemplate to using other framework as jersey

Jersey gives a very handy implementation of such as filter called LoggingFilter which can help in logging all kinds of incoming and outgoing traffic.

Sign up to request clarification or add additional context in comments.

8 Comments

Thanks. I will try a filter and keep you updated! This could be an obvious oversight! And thanks for being concise and straight to the point. Sometimes it's not about why the OP wants to do it, it's just about how to get it done
Servlet filters can only intercept the requests that come INTO the application. I guess what the OP wants is to intercept requests that go OUT of an app via restTemplate. Am I correct @soulshined?
@user7294900 that only tells about intercepting request that come into the controller right? Or am I missing something? Would it intercept requests that go out of the app via resttemplate or any other http client?
@MadhuBhat I update my answer with link you will have to change RestTemplate to using other framework as jersey
|
3

HandlerInterceptorAdapter is an implementation that applies to @Controller or @RestController. Not an implementation for RestTemplete.

To apply it to RestTemplete, you need to use ClientHttpRequestInterceptor.

ex.

@Component public class CustomInterceptor implements ClientHttpRequestInterceptor { @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { // ... } } 
@Configuation public class RestTempleteConfig { // ... @Autowired private CustomInterceptor customInterceptor; @Bean public RestTemplate restTemplate(){ RestTemplate template = new RestTemplate(); List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>(); template.add(customInterceptor); return template; } } 

1 Comment

The OP explicitly mentions this is not a desired solution. And of course I'm using a mixture of Services and RestControllers. Thanks for the feedback though!
1

The HandlerInterceptorAdapter is for the server side (i.e. RestController) to intercept some important events when server processes a HTTP request , it is nothing to do with what HTTP client (e.g RestTemplate) is used.

If you want to use RestTemplate as a HTTP client and want to intercept the request just before it sent out and the response just after it received , you must use ClientHttpRequestInterceptor.

I’m trying to intercept requests and responses in a more flexible way than ClientHttpRequestInterceptor.

From your comment above , what is your actual use-cases that it cannot handle ? I think ClientHttpRequestInterceptor is already quite flexible enough to implement any complex logic to intercept request and response. As your question does not provide any information about how you need to intercept , I can only give a general example to show what the ClientHttpRequestInterceptor can offer .

To configure the RestTemplate to use an interceptor :

RestTemplate rt = new RestTemplate(); List<ClientHttpRequestInterceptor> interceptors= new ArrayList<ClientHttpRequestInterceptor>(); inteceptors.add(new MyClientHttpRequestInterceptor()); 

And the ClientHttpRequestInterceptor looks like:

public class MyClientHttpRequestInterceptor implements ClientHttpRequestInterceptor{ @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { //The HTTP request and its body are intercepted here which you can log them or modify them. e.g. System.out.println("Log the HTTP request header: " + request.getHeaders()); //Modify the HTTP request header.... request.getHeaders().add("foo", "fooValue"); //Throw exception if you do not want to send the HTTP request //If it is at the end of the interceptor chain , call execution.execute() to confirm sending the HTTP request will return the response in ClientHttpResponse //Otherwise, it will pass the request to the next interceptor in the chain to process ClientHttpResponse response= execution.execute(request, body); //The HTTP response is intercepted here which you can log them or modify them.e.g. System.out.println("Log the HTTP response header: " + response.getHeaders()); //Modify the HTTP response header response.getHeaders().add("bar", "barValue"); return response; } } 

Please note that you can also configure a chain of ClientHttpRequestInterceptor which allows to split some complex request and response intercept logic into many smalls and reusable ClientHttpRequestInterceptor. It is designed with the Chain of responsibility design pattern which its API experience is very similar to what Filter#doFilter() in Servlet.

5 Comments

im completely with you. perhaps he can/could/should create a class that implements both interfaces an/or inherit from an abstract super-class that holds similarities?
The things that I don't quite understand is that if OP just want to intercept the request / response when using a HTTP client , how does it matter and why need to care how the server intercept the request / response ?
i have read all answers and comments and i also dont really understand. on one hand hes afraid of deprecation, on the other he rather uses RestTemplatethan WebClient. the api dictates its requirements and we have to fit these requirement. my suggestion was/is my best guess, what he might want to achieve.
I'm not afraid of deprecation, as I mentioned, versioning is beyond my control and ClientHttpRequestInterceptor does not work for my needs, lets even just say for arbitrary reasons for the sake of argument. Why it doesn't is irrelevant and would absolutely be against SO etiquette by asking a question 'too broad' or 'not sure what you're asking'. I've narrowed the ask down to something very simple, intercept requests/responses with RestTemplate that's not ClientHttpRequestInterceptor. At the end of the day it doesn't matter why, the ask is how.
@soulshined , understand. So how do your final solution become ? I re-read the accept answer and still cannot find any information about how to do it with RestTemplate without using ClientHttpRequestInterceptor . Do I miss something here ?🤔🤔 Can you share your final solution such that community here can learn a way to intercept which may be better than the existing ClientHttpRequestInterceptor way provided by RestTemplate? 🙇‍♂️🙇‍♂️🙇‍♂️ Thanks.
0

As @WonChulHeo noted you can't use HandlerInterceptorAdapter with RestTemplate. Only ClientHttpRequestInterceptor. It's not clear why do you need exactly HandlerInterceptorAdapter - we can only see that you are trying to log the fact of the request interception. And ClientHttpRequestInterceptor is absolutely able to do the same and even more - check my working example bellow.

P.S. There is an error in your code - you can't use private access for @Bean methods - check your private RestTemplate restTemplate() { please...

@Slf4j @RestController @SpringBootApplication public class Application { public static void main(String[] args) { new SpringApplicationBuilder(Application.class) .bannerMode(Banner.Mode.OFF) .run(args); } @GetMapping("/users/{id}") public User get(@PathVariable int id) { log.info("[i] Controller: received request GET /users/{}", id); return new User(id, "John Smith"); } @Bean public RestTemplate restTemplate(RestTemplateBuilder templateBuilder) { ClientHttpRequestFactory requestFactory = new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()); return templateBuilder .interceptors((request, bytes, execution) -> { URI uri = request.getURI(); HttpMethod method = request.getMethod(); log.info("[i] Interceptor: requested {} {}", method, uri); log.info("[i] Interceptor: request headers {}", request.getHeaders()); ClientHttpRequest delegate = requestFactory.createRequest(uri, method); request.getHeaders().forEach((header, values) -> delegate.getHeaders().put(header, values)); ClientHttpResponse response = delegate.execute(); log.info("[i] Interceptor: response status: {}", response.getStatusCode().name()); log.info("[i] Interceptor: response headers: {}", response.getHeaders()); String body = StreamUtils.copyToString(response.getBody(), Charset.defaultCharset()); log.info("[i] Interceptor: response body: '{}'", body); return response; }) .rootUri("http://localhost:8080") .build(); } @Bean ApplicationRunner run(RestTemplate restTemplate) { return args -> { ResponseEntity<User> response = restTemplate.getForEntity("/users/{id}", User.class, 1); if (response.getStatusCode().is2xxSuccessful()) { log.info("[i] User: {}", response.getBody()); } else { log.error("[!] Error: {}", response.getStatusCode()); } }; } } 
@Data @AllArgsConstructor @NoArgsConstructor public class User { private int id; private String name; } 

1 Comment

Thanks for the input. As noted, I'm not trying to use ClientHttpRequestInterceptor, and the reasons why are a unique edge case that wouldn't be helpful to future readers and could potentially solicit answers that aren't applicable.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.