Я читал об исключениях на основе контроллеров, использующих @ExceptionHandler.
Я читал о глобальной обработке исключений с помощью @ControllerAdvice.
Я также читал о расширении HandlerExceptionResolver для более глубокой обработки исключений.
Однако в идеале я хотел бы иметь возможность генерировать глобальное исключение с параметрами, которые определяют ответ JSON, возвращаемый клиенту, на любом уровне в моем приложении.
Например:
throw new CustomGlobalException(HttpStatus.UNAUTHORISED, "This JWT Token is not Authorised.")
throw new CustomGlobalException(HttpStatus.FORBIDDEN, "This JWT Token is not valid.")
Затем будет возвращен ответ JSON на основе созданной мной модели вместе со статусом, например:
{
"success" : "false",
"message" : "This JWT Token is not Authorised."
}
И чтобы это было возвращено как ответ REST от моего контроллера. Возможно ли что-то подобное? Или мне нужно пройти процесс создания пользовательских исключений ошибок для всего, как описано в документации.
Чтобы уточнить, мне нужно, чтобы исключение прервало текущий процесс, например, получение данных из базы данных, и немедленно вернуло данное исключение клиенту. У меня есть настройка веб-mvc.
Дальнейшие подробности:
@ControllerAdvice
@RequestMapping(produces = "application/json")
public class GlobalExceptionHandler {
@ExceptionHandler(CustomException.class)
public ResponseEntity<Object> handleCustomException(CustomException ex,
WebRequest request) {
Map<String, Object> response = new HashMap<>();
response.put("message", ex.getMessage());
return new ResponseEntity<>(response, ex.getCode());
}
}
Здесь выброшено исключение:
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain
filterChain) throws ServletException, IOException {
logger.debug("Filtering request for JWT header verification");
try {
String jwt = getJwtFromRequest(request);
logger.debug("JWT Value: {}", jwt);
if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
String username = tokenProvider.getUserIdFromJWT(jwt);
UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken
(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
} else {
logger.error("No Valid JWT Token Provided");
throw new CustomException(HttpStatus.UNAUTHORIZED, "No Valid JWT Token Provided");
}
} catch (Exception ex) {
logger.error("Could not set user authentication in security context", ex);
}
filterChain.doFilter(request, response);
}
Это не совсем то, что вы хотите достичь, но самый простой способ сделать почти то, что вы хотите (и чище, IMO), - просто определить исключение, подобное следующему:
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public class UnauthorizedException extends RuntimeException {
public UnauthorisedException(String message) {
super(message);
}
}
Теперь каждый раз, когда такое исключение генерируется (не возвращается) из метода контроллера (прямо или косвенно), вы будете получать такой ответ, как
{
"timestamp": "2018-06-24T09:38:51.453+0000",
"status": 401,
"error": "Unauthorized",
"message": "This JWT Token is not Authorised.",
"path": "/api/blabla"
}
И, конечно же, фактический код состояния ответа HTTP также будет 401.
Вы также можете выбросить ResponseStatusException, который является более общим и позволяет использовать тот же тип исключения и передавать статус в качестве аргумента. Но я считаю его менее чистым.
Однако у меня такая же проблема, возможно, я не понимаю. Я хотел бы, чтобы в любой момент моего кода было создано исключение UnauthorisedException, и текущий процесс должен быть прерван, а исключение немедленно возвращено клиенту. Однако это не вызывает и этого, я просто получаю исключение, после чего оно все равно продолжает выполняться.
Если он продолжает выполняться, это означает, что вы каким-то образом перехватили исключение. Не делайте этого и позвольте исключению всплыть, пока Spring не поймает его и не отправит клиенту указанный выше JSON.
Следуя моему сообщению о том, как обрабатывать исключение здесь, вы можете написать свой собственный обработчик примерно так:
class CustomGlobalException {
String message;
HttpStatus status;
}
@ExceptionHandler(CustomGlobalException.class)
public ResponseEntity<Object> handleCustomException(CustomGlobalException ex,
WebRequest request) {
Map<String, Object> response = new HashMap<>();
response.put("success", "false");
response.put("message", ex.getMessage());
return new ResponseEntity<>(response, ex.getStatus());
}
Упомянутый выше код будет обрабатывать CustomGlobalException на любом уровне кода.
Это идеальный вариант, но он не будет возвращен клиенту. Другими словами, если я настрою это и выброшу CustomGlobalException, информация будет записана в журнал, но остальная часть функции продолжит выполнение.
> Остальная часть функции продолжит выполнение. вы можете подробнее рассказать?
Пользователь отправляет запрос на мой сервер отдыха. Проходит через контроллер, вызывает уровень сервиса. Уровень обслуживания находит проблему, выдает исключение CustomException. На этом этапе исключение регистрируется. Но метод продолжает работу и возвращает данные пользователю, когда он должен был немедленно вернуть ошибку.
Нет. То, как я это сделал, не выполнит остальную часть кода. В этом случае выполнение метода будет остановлено, и клиенту вернется ошибка. Пользователь увидит o / p вернуть новый ResponseEntity <> (ответ, например getStatus ()); в случае ошибки. Примечание. Этот способ обработки исключения, который я использую в своем проекте, сработал, как я сказал. Если это не сработает, оставьте код, который вы пытаетесь. Я бы хотел увидеть..
Я добавил более подробную информацию. Я получаю ответ 200 с запросом данных от пользователя, даже если аутентификация не предусмотрена.
ОК. Я зарегистрировался в своем проекте. Infect возникает аналогичная ситуация, когда мне нужно проверить учетные данные клиента. Как я объясняю, это работает. Я видел твой код. Я прошу вас внести следующие изменения и проверить еще раз. Измените свой GlobalExceptionHandler, как указано ниже. @RestControllerAdvice @RequestMapping (производит = "application / json") открытый класс GlobalExceptionHandler расширяет ResponseEntityExceptionHandler {} и использует CustomException в @ExceptionHandler (CustomGlobalException.class) (в данном фрагменте кода)
По-прежнему не повезло ... Есть ли у вас публичное репо? Кроме того, возможно, существуют какие-либо другие требования к конфигурации, например установка ExceptionHandler в web.xml или что-то подобное?
Нет, нет. Если у вас есть код в публичном репо, дайте мне знать URL. Сделаю оттуда ветку и внесу все необходимые изменения.
Я создал для вас демонстрационный проект, и он работает как положено. Вот ссылка github.com/shauank/spring-boot/tree/master/demo
Я просто ловил исключение выше (фейспалм). Вы действительно вышли за рамки Шаунака, спасибо ...
Начиная с Spring 5 и более поздних версий, ResponseStatusException (предоставляется Spring framework) было бы лучше. Пожалуйста, обратитесь к весна-ответ-статус-исключение
Спасибо за ответ. Я также согласен, мне не нравится передавать статус в качестве параметра и оставлять фактическое исключение ошибки неизменным. Я разберусь с этим, спасибо!