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.