How can I return an error message and HTTP status code that calls jQuery AJAX error function?
Solution 1
I don't know how exactly you are making the requests to the server. But this is how I would do it.
@ExceptionHandler(Exception.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR, reason = "your message")
public void handleException(IllegalStateException ex, HttpServletResponse response) throws IOException
{
}
In in the client side
$.ajax({
type : "POST",
url : urlString,
data : params,
dataType : 'json',
success : function(data) {
// do something}
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.status); //This will be 500
alert(xhr.responseText); // your message
//do stuff
}
Solution 2
In Spring 3.2 you can put your exception handler inside a @ControllerAdvice
annotated class.
Classes annotated with
@ControllerAdvice
can contain@ExceptionHandler
,@InitBinder
, and@ModelAttribute
methods and those will apply to@RequestMapping
methods across controller hierarchies as opposed to the controller hierarchy within which they are declared.@ControllerAdvice
is a component annotation allowing implementation classes to be auto-detected through classpath scanning.
So if your controllers are picked up by autoscanning @Controller
annotated classes, @ControllerAdvice
should also work(if you scan @Controller
classes with an explicit annotation expression, you may need to register this bean separately).
@ControllerAdvice
public class AppControllerAdvice{
@ExceptionHandler(Throwable.class)
ResponseEntity<String> customHandler(Exception ex) {
return new ResponseEntity<String>(
"Custom user message",
HttpStatus.INTERNAL_SERVER_ERROR);
}
Please note that the text is a part of the returned entity and not an HTTP reason phrase.
Solution 3
Here is how I did it.
public class CustomExceptionResolver extends AbstractHandlerExceptionResolver {
private static final Logger logger = Logger.getLogger(CustomExceptionResolver.class);
protected ModelAndView doResolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
try {
response.reset();
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.setCharacterEncoding("UTF-8");
response.setContentType("text/json");
MappingJacksonJsonView view = new MappingJacksonJsonView();
Map<String, String> asd = new HashMap<String, String>();
asd.put("message", ex.getMessage());
view.setAttributesMap(asd);
return new ModelAndView(view);
} catch (Exception e) {
logger.error("send back error status and message : " + ex.getMessage(), e);
}
return null;
}
And then of course in my json-servlet.xml file:
<bean id="exceptionResolver" class="com.autolytix.common.web.CustomExceptionResolver"/>
James
Updated on November 04, 2020Comments
-
James over 3 years
Using Spring, I have a SimpleMappingExceptionResolver that catches any unexpected exceptions in my application in the resolveException method. In the method, I return a ModelAndView that gives error message text back to the HTTP client. Here's the code:
public class UnExpectedExceptionResolver extends SimpleMappingExceptionResolver { private Log logger = LogFactory.getLog(this.getClass().getName()); private ResourceBundleMessageSource messageSource; @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) { // let the end user know that an error occurred Locale locale = RequestContextUtils.getLocale(request); String messageText = messageSource.getMessage("systemError", null, locale); Message message = new Message(messageText, MessageType.ERROR); ModelAndView mav = new ModelAndView(); mav.setView(new MappingJacksonJsonView()); mav.addObject("message", message); return mav; }
As such, the response is returned with a HTTP status code of 200 with response text being the message (JSON). Unfortunately, the client thinks it's a valid response due to the 200 code and tries to process it as such. I tried setting the HTTP status code to 500 as follows:
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Server Error");
right before the
return mav;
statement. Unfortunately, this returns a HTML page indicating a internal error instead of my JSON message. How can I return the JSON message and still indicate a server error (or some type of error) to the client? Specifically, I expect the client's error function in the AJAX call to be invoked and still have the message data sent back to the client. FYI - I'm using jQuery on the client side.