Страница и Ajax вызывают обработку весенних исключений

#ajax #rest #jsp #spring-mvc

#ajax #rest #jsp #spring-mvc

Вопрос:

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

Какой был бы удобный метод для обработки как необработанных исключений запроса страницы, так и необработанных исключений ajax-вызовов в одном приложении?

Это может быть проблемой, поскольку глобальный обработчик исключений также перехватывает вызовы ajax и возвращает «выделенную страницу ошибок» с большим количеством информации и, таким образом, не позволяет выдавать тонкий ответ об ошибке для обратного вызова ajax error.

Комментарии:

1. Вызов AJAX может быть вызовом REST, но я предполагаю, что вы имеете в виду запрос страницы против Запрос AJAX. Я не понимаю вопрос 1. Поскольку вы знаете, как писать обработчики исключений, я не уверен, каковы ваши намерения в вопросе 2.

Ответ №1:

Существует три способа обработки исключений в контроллерах rest:

Аннотируйте свои исключения с помощью @ResponseStatus и правильного кода результата HTTP, который должен быть возвращен при возникновении данного исключения.

Например. Если выдается personnotfoundexception, верните http 404 клиенту (не найден)

 @ResponseStatus(HttpStatus.NOT_FOUND)
public class PersonNotFoundException { … }
  

Другой способ — иметь метод, аннотированный с помощью @ExceptionHandler в вашем контроллере. В значении аннотации @ExceptionHandler вы определяете, какие исключения должны быть перехвачены. Кроме того, вы можете добавить аннотацию @ResponseStatus к тому же методу, чтобы определить, какой код результата HTTP должен быть возвращен клиенту.

 @ResponseStatus(HttpStatus.NOT_FOUND)
@ExceptionHandler({PersonNotFoundException.class})
public void handlePersonNotFound() {
  ...
}
  

Предпочтительный метод: реализация интерфейса ResponseEntityExceptionHandler в качестве @ControllerAdvice. Таким образом, вы можете применить логику обработки исключений ко всем контроллерам с централизованной обработкой исключений. Вы можете прочитать больше в руководстве здесь.

 @ControllerAdvice
public class CustomResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
    ...
    @Override
    protected ResponseEntity<Object> handleHttpMediaTypeNotSupported(HttpMediaTypeNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        String unsupported = "Unsupported content type: "   ex.getContentType();
        String supported = "Supported content types: "   MediaType.toString(ex.getSupportedMediaTypes());
        ErrorMessage errorMessage = new ErrorMessage(unsupported, supported);
        return new ResponseEntity(errorMessage, headers, status);
    }
    ...
}
  

Обратите внимание, что вы не должны возвращать generic 500 - Internal server error для всех типов исключений. Как правило, вы хотите иметь диапазон результатов 400s для ошибок клиента — неправильный запрос. И 500-секундный диапазон кодов результатов для ошибок на стороне сервера. Кроме того, лучше возвращать более конкретные коды в зависимости от того, что произошло, а не просто 400 или 500.

Комментарии:

1. Как @ControllerAdvice сопоставляется с @Controller . Как исключение в контроллере сопоставляется с исключением?

2. Он является общим для всех контроллеров, а не для каждого контроллера, поэтому вы можете иметь централизованную обработку исключений. Соответствующий метод вызывается автоматически на основе типа исключения (входного параметра).

Ответ №2:

Я пришел к решению разделить вызовы ajax и запрос порядковой страницы в глобальном обработчике исключений с использованием заголовков запросов. Существуют также разные ответы на ошибки для исключений типа ajax с недопустимым пользовательским вводом и внутренних ошибок сервера.

 ...
public class Application extends SpringBootServletInitializer {

@Bean(name = "simpleMappingExceptionResolver")
public SimpleMappingExceptionResolver createSimpleMappingExceptionResolver() {
    SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver();
    r.setDefaultErrorView("forward:/errorController");
    return r;
}
  

 @Controller
public class ErrorController {

    public static final Logger LOG = Logger.getLogger(ErrorController.class);

    @RequestMapping(value = "/errorController")
    public ModelAndView handleError(HttpServletRequest request,
            @RequestAttribute("exception") Throwable th) {

        ModelAndView mv = null;
        if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) {
            if (isBusinessException(th)) {
                mv = new ModelAndView("appAjaxBadRequest");
                mv.setStatus(BAD_REQUEST);
            } else {
                LOG.error("Internal server error while processing AJAX call.", th);
                mv = new ModelAndView("appAjaxInternalServerError");
                mv.setStatus(INTERNAL_SERVER_ERROR);
            }
            mv.addObject("message", getUserFriendlyErrorMessage(th).replaceAll("r?n", "<br/>"));
        } else {
            LOG.error("Cannot process http request.", th);
            mv = new ModelAndView("appErrorPage");
            mv.addObject("exeption", th);
        }

        return mv;
    }
}