如何返回调用jQuery AJAX错误函数的错误消息和HTTP状态代码?

时间:2021-04-18 20:33:00

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:

使用Spring,我有一个SimpleMappingExceptionResolver,可以在resolveException方法中捕获应用程序中的任何意外异常。在该方法中,我返回一个ModelAndView,它将错误消息文本提供给HTTP客户端。这是代码:

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:

因此,响应将返回HTTP状态代码200,响应文本为消息(JSON)。不幸的是,由于200代码,客户认为这是一个有效的响应,并试图像这样处理它。我尝试将HTTP状态代码设置为500,如下所示:

 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.

声明。不幸的是,这会返回一个HTML页面,指示内部错误而不是我的JSON消息。如何返回JSON消息并仍向客户端指示服务器错误(或某种类型的错误)?具体来说,我希望调用AJAX调用中的客户端错误函数,并将消息数据发送回客户端。仅供参考 - 我在客户端使用jQuery。

4 个解决方案

#1


10  

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
  }

#2


6  

In Spring 3.2 you can put your exception handler inside a @ControllerAdvice annotated class.

在Spring 3.2中,您可以将异常处理程序放在@ControllerAdvice注释类中。

From Spring 3.2 documenation

从Spring 3.2文档开始

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.

使用@ControllerAdvice注释的类可以包含@ ExceptionHandler,@ InitBinder和@ModelAttribute方法,这些方法将应用于跨控制器层次结构的@RequestMapping方法,而不是声明它们的控制器层次结构。 @ControllerAdvice是一个组件注释,允许通过类路径扫描自动检测实现类。

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).

因此,如果通过自动扫描@Controller注释类来获取控制器,@ ControllerAdvice也应该工作(如果使用显式注释表达式扫描@Controller类,则可能需要单独注册此bean)。

@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.

请注意,文本是返回实体的一部分,而不是HTTP原因短语。

#3


4  

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:

然后当然在我的json-servlet.xml文件中:

<bean id="exceptionResolver" class="com.autolytix.common.web.CustomExceptionResolver"/>

#4


0  

Add the following code to the frontcontrol

将以下代码添加到frontcontrol

 @ExceptionHandler(Exception.class)
public @ResponseBody
MyErrorBean handleGeneralException(Exception e,
        HttpServletRequest request, HttpServletResponse response) {
    logger.info("Exception:" , e);
    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
    MyErrorBean errorBean = new MyErrorBean();
    errorBean.setStatus(MyConstants.ERROR_STATUS);
    return errorBean;

}`

Since you are using JSON I assume you will have a messageconverter configured in your code which will convert this to JSON. By setting the status and sending a bean you will be able to solve it.

由于您使用的是JSON,我假设您将在代码中配置messageconverter,并将其转换为JSON。通过设置状态并发送bean,您将能够解决它。

#1


10  

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
  }

#2


6  

In Spring 3.2 you can put your exception handler inside a @ControllerAdvice annotated class.

在Spring 3.2中,您可以将异常处理程序放在@ControllerAdvice注释类中。

From Spring 3.2 documenation

从Spring 3.2文档开始

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.

使用@ControllerAdvice注释的类可以包含@ ExceptionHandler,@ InitBinder和@ModelAttribute方法,这些方法将应用于跨控制器层次结构的@RequestMapping方法,而不是声明它们的控制器层次结构。 @ControllerAdvice是一个组件注释,允许通过类路径扫描自动检测实现类。

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).

因此,如果通过自动扫描@Controller注释类来获取控制器,@ ControllerAdvice也应该工作(如果使用显式注释表达式扫描@Controller类,则可能需要单独注册此bean)。

@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.

请注意,文本是返回实体的一部分,而不是HTTP原因短语。

#3


4  

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:

然后当然在我的json-servlet.xml文件中:

<bean id="exceptionResolver" class="com.autolytix.common.web.CustomExceptionResolver"/>

#4


0  

Add the following code to the frontcontrol

将以下代码添加到frontcontrol

 @ExceptionHandler(Exception.class)
public @ResponseBody
MyErrorBean handleGeneralException(Exception e,
        HttpServletRequest request, HttpServletResponse response) {
    logger.info("Exception:" , e);
    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
    MyErrorBean errorBean = new MyErrorBean();
    errorBean.setStatus(MyConstants.ERROR_STATUS);
    return errorBean;

}`

Since you are using JSON I assume you will have a messageconverter configured in your code which will convert this to JSON. By setting the status and sending a bean you will be able to solve it.

由于您使用的是JSON,我假设您将在代码中配置messageconverter,并将其转换为JSON。通过设置状态并发送bean,您将能够解决它。