What I want to do is, adding a new header to the response after the request is processed. I need to check the processed HttpStatus
code (401 unauthorized in my case) and add a new header. I know Spring has interceptors, but the response cannot be modified as stated in the document:
Note that the postHandle method of HandlerInterceptor is not always ideally suited for use with @ResponseBody and ResponseEntity methods. In such cases an HttpMessageConverter writes to and commits the response before postHandle is called which makes it impossible to change the response, for example to add a header. Instead an application can implement ResponseBodyAdvice and either declare it as an @ControllerAdvice bean or configure it directly on RequestMappingHandlerAdapter.
Well, I implemented the ResponseBodyAdvice
. Yes, it allows body modification, but I couldn't manage to modify the headers, event couldn't find the status code returned from the controller.
The other option, using servlet filters is not also successful. I need to add the header after filterChain.doFilter(servletRequest, servletResponse);
call. But it again doesn't modify the header value. Is there a way to accomplish this easy task?
Well, Java shows you the HTTP response as an Object for which you can alter the different fields independently.
But what is actually exchanged between the server and the client is a byte stream, and headers and sent before the body. That is the reason why the HttpResponse has the
isCommitted()
method : the response is committed when headers have been sent. And of course once it is committed, you can no longer add of modify headers. And the servlet container may commit and flush the response once enough characters have been written to the body.So trying to change headers is unsafe after the request have been processed. It could work only if request has not been committed. The only case where it is safe is when the controller does not write the response itself and just forwards to a view. Then in the
postHandle
interceptor method, the response has not been committed, and you can change headers. Otherwise, you must testisCommitted()
, and if it returns true ... then it is too late to change headers !Of course in that case, neither an interceptor nor a filter could do anything ...
It sounds like you're on the right track with a servlet filter, what you probably need to do is wrap the servlet response object with one that detects when a 401 status code has been set and adds your custom header at that time:
Well, actually you can if you cast that
ServerHttpResponse
toServletServerHttpResponse
.(It must be
ServletServerHttpResponse
based on the how theResponseBodyAdvice
is called , you can see thatServerHttpResponse
passed toResponseBodyAdvice
is actually anServletServerHttpResponse
in this method).So simply implement a
ResponseBodyAdvice
and no need to wrap theHttpServletResponse
anymore :You can implement a ServletFilter and just wrap the original response object.
This will allow you to defer the actual writing of the response and add your custom headers.
On the other hand: This looks a bit like the Spring Security Processing chain.
If checking status code is not required then you can just add those headers on preHandle method (as Spring commits response before postHandle fires, so adding them in postHandle will not work for response returned from @ResponseBody marked controller method):