Tomcat中部署的Spring引导应用程序中的@ExceptionHandler没有返回@ResponseBody

Posted

技术标签:

【中文标题】Tomcat中部署的Spring引导应用程序中的@ExceptionHandler没有返回@ResponseBody【英文标题】:No @ResponseBody returned from @ExceptionHandler in Spring boot app deployed in Tomcat 【发布时间】:2015-05-18 11:15:24 【问题描述】:

我有一个 Spring Boot Web 应用程序,它在 STS 中运行良好,但在 Tomcat 中从 WAR 文件运行时显示不同的行为。

我使用 Thymeleaf 处理我的所有网页,但我有几个页面使用 jQuery 发送异步调用并使用户体验更加动态。

无论如何,我有一个 Controller 方法调用一个服务方法,它可能会抛出一个 RuntimeException 我以这种方式处理:

@ExceptionHandler(MyRuntimeException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public @ResponseBody String handleMyRuntimeException(MyRuntimeException exception) 
    return "Oops an error happened : " + exception.getMessage();

在 JS 中,我使用上面返回的响应正文在屏幕上显示消息。

在 STS 中运行我的应用程序时效果很好,但是一旦我切换到在 Tomcat 中部署它,ErrorPageFilter 就会被调用,而在 doFilter() 中它会:

if (status >= 400) 
    handleErrorStatus(request, response, status, wrapped.getMessage());
    response.flushBuffer();

handleErrorStatus() 中,它会在状态和相关消息中创建一个错误,但不会返回我的响应。

我还没有想出如何解决这个问题,如果有人可以提供帮助,我将不胜感激。

谢谢!

【问题讨论】:

目前,我的解决方法是捕获我的服务抛出的异常并返回一个带有 SUCCESS 或 FAILURE 状态以及相应消息和/或结果数据的 JSON 对象。 【参考方案1】:

我通过执行以下操作解决了这个问题(我认为这是一个 Spring Boot 问题)。

    单独的 Rest 和 Mvc 控制器 在这里查看我的问题:Spring MVC: Get i18n message for reason in @RequestStatus on a @ExceptionHandler

    注入 Jackson 转换器并自己编写响应:

    @ControllerAdvice(annotations = RestController.class)
    @Priority(1)
    @ResponseBody
    public class RestControllerAdvice 
        @Autowired
        private MappingJackson2HttpMessageConverter jacksonMessageConverter;
    
        @ExceptionHandler(RuntimeException.class)
        @ResponseStatus(value = HttpStatus.BAD_REQUEST)
        public void handleRuntimeException(HttpServletRequest request, HttpServletResponse response, RuntimeException exception) 
            try 
                jacksonMessageConverter.write(new MyRestResult(translateMessage(exception)), MediaType.APPLICATION_JSON, new ServletServerHttpResponse(response));
                response.flushBuffer(); // Flush to commit the response
                 catch (IOException e) 
                e.printStackTrace();
            
        
    
    

【讨论】:

调用flushBuffer()方法很重要,否则这将不起作用。 真正不同的是您删除了@ResponseStatus(请参阅jira.spring.io/browse/SPR-8251)。相反,您可以简单地返回一个 ResponseEntity。没有必要通过杰克逊写自己。 我会试试的,谢谢!但是,如果我在我的 ResponseEntity 中返回 HttpStatus.BAD_REQUEST,我不会得到相同的行为吗? 返回一个新的 ResponseEntity(myRestResult, HttpStatus.BAD_REQUEST) 产生相同的结果。我将记录一个引导问题。感谢您的宝贵时间。 @DamienPolegato 非常感谢您的代码。我的@RestControllerAdvice 带注释的全局异常处理程序将正确地将ResponseEntity 作为JSON 传递给客户端,但它不会在@ExceptionHandler(value = ConstraintViolationException.class) 的处理程序上将其传递给客户端。你的解决方案让我给客户一个个性化的 Repsonse 约束。

以上是关于Tomcat中部署的Spring引导应用程序中的@ExceptionHandler没有返回@ResponseBody的主要内容,如果未能解决你的问题,请参考以下文章

Tomcat中的spring-boot应用程序战争部署,现有的spring web应用程序失败

两个springboot项目如何部署在同一个服务上,两个spring启动应用程序部署在同一台服务器上

如何在 Spring Boot 应用程序中启用 HTTPS,在 Tomcat 中部署为 WAR 文件?

Spring Boot Tomcat 容器部署错误

Spring MVC项目无法部署到tomcat中运行。

在 Tomcat 6 中部署 Spring Boot 应用程序(传统部署)