Eu quero usar uma maneira genérica de gerenciar códigos de erro 5xx, digamos especificamente o caso em que o banco de dados está baixo em todo o meu aplicativo Spring. Eu quero um belo erro json em vez de um rastreamento de pilha.
Para os controladores eu tenho uma @ControllerAdvice
classe para as diferentes exceções e isso também está pegando o caso que o db está parando no meio da requisição. Mas isto não é tudo. Acontece que eu também tenho uma CorsFilter
extensão personalizada OncePerRequestFilter
e quando ligo doFilter
recebo o CannotGetJdbcConnectionException
e não será gerenciado pelo @ControllerAdvice
. Eu li várias coisas online que só me deixaram mais confuso.
Então, eu tenho muitas perguntas:
- Eu preciso implementar um filtro personalizado? Eu encontrei o
ExceptionTranslationFilter
mas isso só alçaAuthenticationException
ouAccessDeniedException
. - Pensei em implementar o meu próprio
HandlerExceptionResolver
, mas fiquei em dúvida, não tenho nenhuma exceção customizada para gerenciar, deve haver uma forma mais óbvia do que essa. Também tentei adicionar um try / catch e chamar uma implementação deHandlerExceptionResolver
(deve ser bom o suficiente, minha exceção não é nada especial), mas isso não está retornando nada na resposta, recebo um status 200 e um corpo vazio.
Existe alguma boa maneira de lidar com isso? obrigado
fonte
Respostas:
Então foi isso que eu fiz:
Eu li o básico sobre filtros aqui e descobri que preciso criar um filtro personalizado que será o primeiro na cadeia de filtros e terá uma captura de tentativa para capturar todas as exceções de tempo de execução que podem ocorrer lá. Em seguida, preciso criar o json manualmente e colocá-lo na resposta.
Então, aqui está meu filtro personalizado:
E então eu adicionei no web.xml antes do
CorsFilter
. E funciona!fonte
Eu queria fornecer uma solução baseada na resposta de @kopelitsa . As principais diferenças são:
HandlerExceptionResolver
.Primeiro, você precisa ter certeza de que tem uma classe que lida com exceções que ocorrem em um RestController / Controller regular (uma classe anotada com
@RestControllerAdvice
ou@ControllerAdvice
e método (s) anotados com@ExceptionHandler
). Isso lida com suas exceções que ocorrem em um controlador. Aqui está um exemplo usando o RestControllerAdvice:Para reutilizar esse comportamento na cadeia de filtros Spring Security, você precisa definir um Filtro e conectá-lo à sua configuração de segurança. O filtro precisa redirecionar a exceção para o tratamento de exceção definido acima. Aqui está um exemplo:
O filtro criado precisa ser adicionado a SecurityConfiguration. Você precisa conectá-lo à cadeia muito cedo, porque todas as exceções do filtro anterior não serão capturadas. No meu caso, era razoável adicioná-lo antes de
LogoutFilter
. Veja a cadeia de filtros padrão e sua ordem nos documentos oficiais . Aqui está um exemplo:fonte
Eu me deparei com esse problema e executei as etapas abaixo para reutilizar o meu
ExceptionController
que está anotado@ControllerAdvise
paraExceptions
inserido em um filtro registrado.Obviamente, existem muitas maneiras de lidar com a exceção, mas, no meu caso, eu queria que a exceção fosse tratada pelo meu
ExceptionController
porque sou teimoso e também porque não quero copiar / colar o mesmo código (ou seja, tenho algum processamento / registro código emExceptionController
). Eu gostaria de retornar a belaJSON
resposta, assim como o resto das exceções lançadas não de um Filtro.Enfim, consegui fazer uso do meu
ExceptionHandler
e tive que fazer um pouco mais conforme mostrado abaixo nas etapas:Passos
@ControllerAdvise
MyExceptionControllerCódigo de amostra
E agora o exemplo de Spring Controller que lida
Exception
em casos normais (ou seja, exceções que normalmente não são lançadas no nível de Filtro, aquele que queremos usar para exceções lançadas em um Filtro)Compartilhando a solução com aqueles que desejam usar
ExceptionController
paraExceptions
jogar em um filtro.fonte
@Component
classe e usa isso no filtro e no o controlador.answer
esta é uma das maneiras! Não afirmei que seja a melhor maneira. Obrigado por compartilhar sua preocupação @psv. Tenho certeza de que a comunidade apreciaria a solução que você tem em mente :)Então, aqui está o que eu fiz com base em um amálgama das respostas acima ... Já tínhamos uma
GlobalExceptionHandler
anotação com@ControllerAdvice
e eu também queria encontrar uma maneira de reutilizar esse código para lidar com exceções que vêm de filtros.A solução mais simples que encontrei foi deixar o manipulador de exceção sozinho e implementar um controlador de erro da seguinte maneira:
Portanto, quaisquer erros causados por exceções passam primeiro pelo
ErrorController
e são redirecionados para o manipulador de exceções, lançando-os novamente de dentro de um@Controller
contexto, enquanto quaisquer outros erros (não causados diretamente por uma exceção) passam peloErrorController
sem modificação.Alguma razão para que isso seja realmente uma má ideia?
fonte
@Override public String getErrorPath() { return null; }
Se você quiser uma forma genérica, pode definir uma página de erro em web.xml:
E adicione mapeamento no Spring MVC:
fonte
Esta é a minha solução substituindo Spring Boot / manipulador de erros padrão
fonte
Apenas para complementar as outras respostas finas fornecidas, já que recentemente eu queria um único componente de tratamento de erro / exceção em um aplicativo SpringBoot simples contendo filtros que podem lançar exceções, com outras exceções potencialmente lançadas de métodos de controlador.
Felizmente, parece que não há nada que o impeça de combinar seu conselho de controlador com uma substituição do manipulador de erro padrão do Spring para fornecer cargas de resposta consistentes, permitir que você compartilhe lógica, inspecione exceções de filtros, intercepte exceções lançadas de serviço específico, etc.
Por exemplo
fonte
Quando você quiser testar um estado de aplicação e em caso de algum problema retornar erro HTTP, sugiro um filtro. O filtro abaixo lida com todas as solicitações HTTP. A solução mais curta em Spring Boot com um filtro javax.
Na implementação pode haver várias condições. No meu caso o applicationManager testando se o aplicativo está pronto.
fonte
Depois de ler os diferentes métodos sugeridos nas respostas acima, decidi lidar com as exceções de autenticação usando um filtro personalizado. Consegui lidar com o status e os códigos de resposta usando uma classe de resposta de erro usando o método a seguir.
Criei um filtro personalizado e modifiquei minha configuração de segurança usando o método addFilterAfter e adicionei após a classe CorsFilter.
Classe SecurityConfig
Classe ErrorResponse
fonte
Você pode usar o seguinte método dentro do bloco catch:
Observe que você pode usar qualquer código HttpStatus e uma mensagem personalizada.
fonte
É estranho porque @ControllerAdvice deve funcionar, você está capturando a exceção correta?
Também tente pegar essa exceção no CorsFilter e enviar erro 500, algo como isso
fonte
Filter
não pode ser capturado@ControllerAdvice
porque não pode alcançarDispatcherServlet
.Você não precisa criar um filtro personalizado para isso. Resolvemos isso criando exceções personalizadas que estendem ServletException (que é lançada do método doFilter, mostrado na declaração). Em seguida, eles são detectados e tratados por nosso gerenciador de erros global.
editar: gramática
fonte