@ResponseBody не возвращается из @ExceptionHandler в загрузочном приложении Spring, развернутом в Tomcat

У меня есть веб-приложение Spring Boot, которое отлично работает из STS, но показывает другое поведение при запуске в Tomcat из файла WAR.

Я использую Thymeleaf для обработки всех своих веб-страниц, но у меня есть пара страниц, которые используют jQuery для отправки асинхронных вызовов и повышения динамичности взаимодействия с пользователем.

Во всяком случае, у меня есть метод контроллера, который вызывает метод службы, который может выдать 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() он создает ошибку со статусом и соответствующим сообщением, но не возвращает мой ответ.

Я не понял, как это решить, и я был бы очень признателен, если бы кто-нибудь мог помочь.

Спасибо!


person Damien Polegato    schedule 16.03.2015    source источник
comment
На данный момент мой обходной путь заключается в том, чтобы поймать исключение, созданное моей службой, и вернуть объект JSON со статусом SUCCESS или FAILURE и соответствующим сообщением и/или данными результата.   -  person Damien Polegato    schedule 26.03.2015


Ответы (1)


Я обошел эту проблему (я думаю, что это проблема Spring Boot), выполнив следующие действия.

  1. Отдельные контроллеры Rest и Mvc. См. мой вопрос здесь: /29294909#29294909">Spring MVC: получить сообщение i18n по причине в @RequestStatus в @ExceptionHandler

  2. Введите преобразователь Джексона и напишите ответ самостоятельно:

    @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();
            }
        }
    }
    
person Damien Polegato    schedule 27.03.2015
comment
Важно вызвать метод flushBuffer(), иначе это не сработает. - person Damien Polegato; 27.03.2015
comment
Что действительно имело значение, так это то, что вы удалили @ResponseStatus (см. jira.spring.io/ просмотр/SPR-8251). Вместо этого вы можете просто вернуть ResponseEntity. Нет необходимости писать себя через Джексона. - person Rossen Stoyanchev; 27.03.2015
comment
Я попробую это спасибо! Но если я верну HttpStatus.BAD_REQUEST в свой ResponseEntity, разве я не получу такое же поведение? - person Damien Polegato; 28.03.2015
comment
Возврат нового ResponseEntity‹MyRestResult›(myRestResult, HttpStatus.BAD_REQUEST) дает тот же результат. Я зарегистрирую проблему с загрузкой. Спасибо за ваше время. - person Damien Polegato; 30.03.2015
comment
@DamienPolegato Большое спасибо за ваш код. Мой @RestControllerAdvice аннотированный глобальный обработчик исключений правильно передал бы ResponseEntity клиенту как JSON, но не передал бы его клиенту в обработчике для @ExceptionHandler(value = ConstraintViolationException.class). Ваше решение, позвольте мне предоставить клиенту персонализированный ответ на ограничения. - person JackLeEmmerdeur; 12.11.2020