Почему ExceptionHandlerExceptionResolver делает редирект вместо простого ответа? - PullRequest
0 голосов
/ 21 февраля 2020

Я написал несколько расширений ExceptionHandlerExceptionResolver, он перехватывает все исключения, которые должен, но вместо того, чтобы возвращать только сообщение об ошибке и код состояния HTTP, он делает странное перенаправление своим собственным URL-адресом, созданным на основе запрошенного пользователями URL-адреса. Например:

user's url -> .../myModule/api/myEntity/123 (it's an id)
resolver's redirect url -> .../myModule/api/myEntity/myEntity/123 

Сервер не имеет такого ресурса и, очевидно, он ответит 404.

Вопрос в том, почему он выполняет перенаправление и как его настроить, чтобы он возвращал только сообщение и код состояния?

Мой распознаватель:

public class BusinessLayerExceptionHandler extends ExceptionHandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        ModelAndView wrappedResponse = new ModelAndView();
        wrappedResponse.addObject("errorMessage", ex.getMessage());
        wrappedResponse.setStatus(HttpStatus.BAD_REQUEST);
        return wrappedResponse;
    }
}

Я предполагаю, что использование ModelAndView предполагает перенаправление. По крайней мере, это описание метода, которое я нашел в DispatcherServlet.

...
     * @return a corresponding ModelAndView to forward to
     * @throws Exception if no error ModelAndView found
     */
    protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
            Object handler, Exception ex) throws Exception {
...

Если так, как заставить его вернуть только сообщение об ошибке и код состояния HTTP?

1 Ответ

1 голос
/ 22 февраля 2020

Вы можете вернуть только сообщение об ошибке и код состояния HTTP, создав пользовательский View.

public class YourCustomView implements View {

    private final String errorMessage;

    public YourCustomView(String errorMessage) {
        this.errorMessage = errorMessage;
    }

    @Override
    public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        response.setContentType("text/plain;charset=UTF-8");
        try (PrintWriter pw = response.getWriter()) {
            pw.write(errorMessage);
        }
    }

}

Вам необходимо поместить пользовательский объект View в ModelAndView объект в HandlerExceptionResolver#resolveException.

public class BusinessLayerExceptionHandler implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) {
        ModelAndView wrappedResponse = new ModelAndView();
        wrappedResponse.setStatus(HttpStatus.BAD_REQUEST);
        wrappedResponse.setView(new YourCustomView(ex.getMessage()));
        return wrappedResponse;
    }
}


почему он выполняет перенаправление

Кажется, что Spring распознает имя представления как defaultViewName и пересылает в это (вызывая RequestDispatcher#forward).
В DispatcherServlet#processHandlerException для defaultViewName устанавливается имя представления ModelAndView, возвращаемое resolveException, когда у него нет View объекта. defaultViewName получено от DispatcherServlet#getDefaultViewName, который переводит HTTP-запрос в имя представления.


Другое решение

Я думаю, что вы сможете используйте взамен @ControllerAdvice и @ExceptionHandler. Он также может обрабатывать исключение, выданное контроллером.

@ControllerAdvice
public class YourControllerAdvice {

    @ExceptionHandler
    public ResponseEntity<Map<String, String>> handleBusinessLayerException(
            Exception exception) {
        Map<String, String> body = Map.of("errorMessage", exception.getMessage());
        return ResponseEntity.badRequest().body(body);
    }

}

См. Также

Spring Web MVC документ о HandlerExceptionResolver
Spring Web MVC документ о ControllerAdvice

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...