Reputation: 4706
I'm trying to write a servlet filter that will add headers to the response depending on the status of the request. I know I have to wrap the response with a HttpServletResponseWrapper before passing to the chain.doFilter
but the headers never get sent, so I'm obviously missing something very obvious.
Code looks something like:
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper(httpServletResponse);
chain.doFilter(request, responseWrapper);
if(responseWrapper.getStatus() < 400)
{
responseWrapper.addHeader("X-Custom-Foobar", "abc");
}
}
Is there something I have to capture in the wrapper to prevent the response from going out to the client until the check is complete?
Upvotes: 4
Views: 6424
Reputation: 38290
The order of this code is inverted:
chain.doFilter(request, responseWrapper);
if(responseWrapper.getStatus() < 400)
{
responseWrapper.addHeader("X-Custom-Foobar", "abc");
}
Try this instead:
if(responseWrapper.getStatus() < 400)
{
responseWrapper.addHeader("X-Custom-Foobar", "abc");
}
chain.doFilter(request, responseWrapper);
The doFilter
method does not return to your method until after the response has been sent on the wire.
Upvotes: 0
Reputation: 3305
This is actually possible. But because after calling chain.doFilter(request, response)
the response is already committed, we have to set the headers after receiving the status code, but before the response is committed. Here is an example:
public class HeadersFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,
ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
chain.doFilter(request, new ResponseWrapper(response));
}
public static class ResponseWrapper extends HttpServletResponseWrapper {
public ResponseWrapper(HttpServletResponse response) {
super(response);
}
@Override
public void setStatus(int sc) {
super.setStatus(sc);
// SET YOUR HEADERS HERE
// setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
}
}
@Override
public void destroy() {
}
}
Upvotes: 0
Reputation: 310860
You need to extend HttpResponseWrapper()
and override the appropriate methods. Just using a vanilla HttpResponseWrapper
by itself accomplishes exactly nothing.
Upvotes: 0
Reputation: 4706
So the frustrating part about this spec is that you have to completely intercept the ServletOutputStream
and buffer it. I ended up following the example here :: https://stackoverflow.com/a/11027170/76343
The base class HttpServletResponseWrapper
is a complete passthrough and as soon as the output stream is closed, all further modifications to the response are mute.
Unfortunately there doesn't seem to be a more elegant way to accomplish this.
Upvotes: 2