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