github linkedin
Adding headers to every Spring Boot response
2021-07-25

In this blog post I’ll explain how to add a header to every response sent by Spring Boot. My requirement is that the header is added after the controller method has run. In that case you can’t use Servlet filters, as the headers come before the response body in a HTTP response - when the Servlet filters run, the controller method has already written the response body (it’s committed) and it’s no longer possible to add headers.

So we need to find a Spring way to add headers. Turns out it’s not that easy: there are two different concepts to accomplish that with Spring Boot.

There is the HandlerInterceptor and there is the ResponseBodyAdvice, but what exactly is the difference?

My first idea was to implement ResponseBodyAdvice and the beforeBodyWrite method. When this method is called, the controller method has run and the response is not committed yet. Perfect place to add our custom header:

@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
    response.getHeaders().add("x-timestamp", Instant.now().toString());

    return body;
}

But it turns out that this method doesn’t work with controller methods which are void (or return null). The beforeBodyWrite is called, the body argument is null, but the response.getHeaders().add(...) call has no effect.

To add headers to void controller methods, you’ll have to implement HandlerInterceptor:

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    if (!response.isCommitted()) {
        response.addHeader("x-timestamp", Instant.now().toString());
    }
}

This method is called on methods with return values, too. But in those cases, response.isCommitted() returns true, which means that adding headers isn’t possible anymore. But for void methods or if null is returned, the response is not yet committed and new headers can be added.

So, to conclude: To reliably add headers to all your Spring Boot responses, you’ll have to implement both ResponseBodyAdvice and HandlerInterceptor. ResponseBodyAdvice adds headers for controller methods which return data and HandlerInterceptor adds headers to void or null controller methods. You can implement both interfaces in one class, like I have done in the example code.

The last thing you’ll have to do is to register the HandlerInterceptor with Spring MVC:

@Configuration
class WebMvcConfig implements WebMvcConfigurer {
    private final TestInterceptor testInterceptor;

    WebMvcConfig(TestInterceptor testInterceptor) {
        this.testInterceptor = testInterceptor;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(testInterceptor);
    }
}

The test in the example code proves that it works.


Back to posts