【问题标题】:How can I return an error message and HTTP status code that calls jQuery AJAX error function?如何返回调用 jQuery AJAX 错误函数的错误消息和 HTTP 状态代码?
【发布时间】:2013-01-23 19:58:24
【问题描述】:

使用 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;
}

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

 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Server Error");

就在

之前
 return mav;

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

【问题讨论】:

  • 您使用的是哪个版本的 Spring?这很重要:Spring 3.1+ 似乎支持 @ResponseBody ,如果你只想要响应状态,你可以抛出一个用 @ResponseStatus 装饰的异常。如果你幸运并且使用 Spring 3.2,你可以返回 ResponseEntity
  • 我使用的是 Spring 3.0.5。它支持@ResponseBody。
  • 是的,但不在 '@ExceptionHandler' 注释方法中。恕我直言,您应该考虑切换到 Spring 3.2。如果有什么好的技术,那么 Spring 团队不会引入带有控制器建议的新异常处理程序。
  • 感谢您的建议。我已经切换到 Spring 3.2。我查看了您的“ResponseEntity”和“@ResponseBody”链接(以及下面的答案)。看来我必须将异常处理程序方法放在每个控制器中。如何使用 ResponseEntity 以使异常处理程序存在于一个类中并像 SimpleMappingExceptionResolver 一样从所有控制器中捕获任何意外异常?如果您可以使用 Spring 3.2 提供答案,将不胜感激。

标签: jquery ajax spring exception http-status-codes


【解决方案1】:

我不知道您是如何准确地向服务器发出请求的。 但我就是这样做的。

@ExceptionHandler(Exception.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR, reason = "your message")
public void handleException(IllegalStateException ex, HttpServletResponse response) throws IOException
{
}

在客户端

$.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
  }

【讨论】:

  • 感谢您的回答。正如您在答案中显示的那样,我正在通过 jQuery ajax 发出请求。我应该把handleException方法放在哪里(哪个类)?
  • 视情况而定,如果您只有一个案例,您可以将其放在进行 AJAX 调用的控制器中。如果不编写所有其他控制器扩展的 BaseController。因此,任何异常都会转到该方法并返回 500 错误代码。
  • 参数是什么意思?
  • @user3369592:它是您要发送的值的 json 表示
【解决方案2】:

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

来自Spring 3.2 documenation

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

因此,如果您的控制器是通过自动扫描 @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);

} 

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

【讨论】:

  • 我最喜欢这种方法。我有一组用于各种异常的异常处理程序,并且在我的控制器内部我抛出了真正的 java 异常。通知捕获它们并将它们转换为适当的 HTTP 状态代码和消息。
【解决方案3】:

这就是我的做法。

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;
    }

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

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

【讨论】:

    【解决方案4】:

    在前端控件中添加如下代码

     @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;
    
    }`
    

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

    【讨论】:

      猜你喜欢
      • 2012-09-25
      • 2010-09-29
      • 1970-01-01
      • 2012-11-14
      • 2020-05-29
      • 1970-01-01
      • 1970-01-01
      • 2011-12-02
      • 2012-04-23
      相关资源
      最近更新 更多