This forum is now a read-only archive. All commenting, posting, registration services have been turned off. Those needing community support and/or wanting to ask questions should refer to the Tag/Forum map, and to http://spring.io/questions for a curated list of stackoverflow tags that Pivotal engineers, and the community, monitor.

AnnouncementAnnouncement Module

Collapse

No announcement yet.

Setting response status in HandlerInterceptor.afterCompletion does not workPage Title Module

Setting response status in HandlerInterceptor.afterCompletion does not work

Dec 22nd, 2011, 04:55 PM

I'm sorry if this has already been answered but I spent over an hour perusing forum messages and didn't find anything specific to this topic.

First, the specifics... Spring 3.0.6, configured mostly thru annotations, but with the additional <appname>-servlet.xml in /WEB-INF.

I have a very simple app, let's call it web02, that has a few controllers. I wanted to have a specific set of operations applied to the HttpServletResponse object returning from all of the controller methods.

I looked around and saw that HandlerInterceptors is the way to go with Spring MVC. I wrote mine to do what I want in .afterCompletion(). I also placed the following in WEB-INF/web02-servlet.xml:

In my log output, I see my logging line print "setting response code: 404 ..." so I know this method is getting ran, but when I issue a request from any client, the httpstatus that gets back to the client is always 200! Regardless of what I set this to.

It's almost as if something else is setting the httpstatus after this method. Any light anyone can shed on this would be greatly appreciated.

Well the method is called afterCompletion for a reason... That method is called after the response has been send to the client. So sending a response changing it isn't going to work in the afterCompletion method, you might have some luck in the postHandle method.

Comment

Yes, I actually did try putting the same code in postHandle at first. It had the same results. That's why I tried moving it to afterCompletion. Still, same thing.

I just need to know how to affect the response status in a interceptor. If not in there, then where? Do I have to write a filter? or is there some other class I can register in Spring MVC that allows me to do the same thing?

The problem is that this only might work if the controller does nothing with the request and no view is to be rendered. If there is a view to be rendered it might depend on the view technology (concrete view implementation) used. Also when using annotation (@controller and @RequestMapping) the response code might already have been set by the HandlerAdapter (not sure if setting it again is allowed).

If using annotations you are best to use @ResponseStatus also what is the use case here, why do you want to change the response code?

Comment

Marten, first off, thanks very much for your replies. I really appreciate you taking time.

Ok, the use case is this... No views being rendered from any of the @Controller methods. Pure REST-style web services returning only data objects using @ResponseBody.

I have an abstract base class (WebApiResponse) for all my response objects. This base class contains a couple of common fields. All other subclasses (UserResponse below) add their own specific typed objects that will be in the method returns.

All I wanted to do is for this object to get serialized in the response body, and I wanted the HttpResponse status code to be set to the same code as the one in my serialized return object.

My problem is that with the above mechanism, whether or not the user object is found, the HttpStatus is set to 200 since I'm not throwing any exceptions of any kind. I simply wanted the above UserResponse object to get serialized regardless, then I'd handle the setting the response status in an interceptor.

BTW, just to update you further... Based on your hint about @ResponseStatus, it led me to the docs for @ExceptionHandler that one can register in any controller. I gave it a try, and it achieves the effect I want, but not as clean as I would have liked it.

By doing this I've achieved the desired effect, but as you can see, the @ExceptionHandler method assumes Content-Type="application/json". I suppose I could inject the HttpRequest in there as well and examine the "Accept" header and use the proper object serializer to do the job.

So, my question is... Is this the correct Spring way of achieving the effect I'm looking for?

BTW, my NotFoundException is annotated with "@ResponseStatus (value = HttpStatus.NOT_FOUND)". But if I simply throw that exception WITHOUT declaring my own @ExceptionHandler, Tomcat writes to the response stream its standard 404/NOT FOUND page HTML page contents, which is very ugly and unusable as a standard data return.

Thanks again in advance for your help on this.

-Jac

Comment

I'm actually trying to do the same thing, and I'm stuck in that I don't know how to have spring convert an exception into a json-ready Status object (so Jackson will serialize) at the app level. But if you defined an @ExceptionHandler in the controller and annotate it with @ResponseBody and return a pojo, you should get the effect you are looking for.

The problem is when using @ResponseBody the return is handled by the RequestResponseBodyMethodProcessor which in turn delegates it to a selected HttpMessageConverter. That converter is probably a subclass of AbstractHttpMessageConverter which flushes the output stream meaning the response is already written and as such cannot be changed anymore. You might get it to work with a custom HttpMessageConverter (or modified existing one).