Estou tentando configurar um servidor de serviços REST em larga escala. Estamos usando o Spring Boot 1.2.1 Spring 4.1.5 e o Java 8. Nossos controladores estão implementando o @RestController e as anotações padrão @RequestMapping.
Meu problema é que o Spring Boot configura um redirecionamento padrão para exceções do controlador /error
. Dos documentos:
O Spring Boot fornece um mapeamento / error por padrão que lida com todos os erros de maneira sensata e é registrado como uma página de erro 'global' no contêiner do servlet.
Vindo de anos escrevendo aplicativos REST com Node.js, isso é, para mim, tudo menos sensato. Qualquer exceção gerada por um terminal em serviço deve retornar na resposta. Não consigo entender por que você enviaria um redirecionamento para o que provavelmente é um consumidor do Angular ou JQuery SPA, que está apenas procurando uma resposta e não pode ou não executa nenhuma ação em um redirecionamento.
O que eu quero fazer é configurar um manipulador de erro global que possa ter qualquer exceção - lançado propositalmente a partir de um método de mapeamento de solicitação ou gerado automaticamente pelo Spring (404 se nenhum método de manipulador for encontrado para a assinatura do caminho da solicitação) e retornar um resposta de erro formatada padrão (400, 500, 503, 404) ao cliente sem nenhum redirecionamento MVC. Especificamente, pegaremos o erro, registrá-lo no NoSQL com um UUID e, em seguida, retornar ao cliente o código de erro HTTP correto com o UUID da entrada de log no corpo JSON.
Os documentos têm sido vagos sobre como fazer isso. Parece-me que você precisa criar sua própria implementação ErrorController ou usar o ControllerAdvice de alguma forma, mas todos os exemplos que vi ainda incluem encaminhar a resposta para algum tipo de mapeamento de erro, o que não ajuda. Outros exemplos sugerem que você precisa listar todos os tipos de exceção que deseja manipular, em vez de apenas listar "Throwable" e obter tudo.
Alguém pode me dizer o que eu perdi ou me indicar a direção certa sobre como fazer isso sem sugerir a cadeia com a qual o Node.js seria mais fácil de lidar?
fonte
Respostas:
Nova resposta (20-04-2016)
Usando Spring Boot 1.3.1.RELEASE
Nova Etapa 1 - É fácil e menos invasivo adicionar as seguintes propriedades ao application.properties:
Se estiver trabalhando com um aplicativo RESTful completo, é muito importante desabilitar o mapeamento automático de recursos estáticos, pois se você estiver usando a configuração padrão do Spring Boot para manipular recursos estáticos, o manipulador de recursos manipulará a solicitação (ela é ordenada por último e mapeada para / **, o que significa que ele coleta todas as solicitações que não foram tratadas por nenhum outro manipulador no aplicativo) para que o servlet do despachante não tenha a chance de gerar uma exceção.
Nova resposta (04-12-2015)
Usando o Spring Boot 1.2.7.RELEASE
Nova etapa 1 - Encontrei uma maneira muito menos intrusiva de definir o sinalizador "throExceptionIfNoHandlerFound". Substitua o código de substituição DispatcherServlet abaixo (Etapa 1) por este na sua classe de inicialização do aplicativo:
Nesse caso, estamos definindo o sinalizador no DispatcherServlet existente, que preserva qualquer configuração automática pela estrutura do Spring Boot.
Mais uma coisa que eu encontrei - a anotação @EnableWebMvc é mortal para o Spring Boot. Sim, essa anotação permite capturar todas as exceções do controlador, conforme descrito abaixo, mas também mata MUITAS configurações automáticas úteis que o Spring Boot normalmente forneceria. Use essa anotação com extrema cautela ao usar o Spring Boot.
Resposta original:
Depois de muito mais pesquisa e acompanhamento das soluções postadas aqui (obrigado pela ajuda!) E pouca quantidade de rastreamento do tempo de execução no código Spring, finalmente encontrei uma configuração que tratará de todas as exceções (não erros, mas continue lendo) incluindo 404s.
Etapa 1 - diga ao SpringBoot para parar de usar o MVC para situações de "manipulador não encontrado". Queremos que o Spring lance uma exceção em vez de retornar ao cliente um redirecionamento de exibição para "/ error". Para fazer isso, você precisa ter uma entrada em uma de suas classes de configuração:
A desvantagem disso é que ele substitui o servlet padrão do despachante. Isso ainda não foi um problema para nós, sem efeitos colaterais ou problemas de execução aparecendo. Se você quiser fazer mais alguma coisa com o servlet do expedidor por outros motivos, este é o lugar para fazê-lo.
Etapa 2 - Agora que a inicialização por primavera lançará uma exceção quando nenhum manipulador for encontrado, essa exceção poderá ser tratada com outras pessoas em um manipulador de exceção unificado:
Lembre-se de que a anotação "@EnableWebMvc" é significativa aqui. Parece que nada disso funciona sem ele. E é isso: seu aplicativo de inicialização do Spring agora captura todas as exceções, incluindo 404s, na classe de manipulador acima e você pode fazer o que quiser.
Um último ponto - não parece haver uma maneira de fazer com que isso apareça erros lançados. Eu tenho uma idéia maluca de usar aspectos para capturar erros e transformá-los em exceções com as quais o código acima pode lidar, mas ainda não tive tempo para realmente tentar implementá-lo. Espero que isso ajude alguém.
Quaisquer comentários / correções / melhorias serão apreciados.
fonte
@ExceptionHandler
método chamado ao colocá-lo na@ControllerAdvice
classe, embora eles funcionem corretamente se colocados na@RestController
classe.@EnableWebMvc
está na classe@ControllerAdvice
e@Configuration
(eu testei todas as combinações). Alguma idéia ou exemplo de trabalho? // @Andy WilkinsonCom o Spring Boot 1.4+, novas classes interessantes para facilitar o manuseio de exceções foram adicionadas, ajudando a remover o código padrão.
Um novo
@RestControllerAdvice
é fornecido para manipulação de exceção, é a combinação de@ControllerAdvice
e@ResponseBody
. Você pode remover o@ResponseBody
sobre o@ExceptionHandler
método quando usar esta nova anotação.ie
Para manipular erros 404, adicionar
@EnableWebMvc
anotação e o seguinte a application.properties foi suficiente:spring.mvc.throw-exception-if-no-handler-found=true
Você pode encontrar e brincar com as fontes aqui:
https://github.com/magiccrafter/spring-boot-exception-handling
fonte
@RestControllerAdvice
sem configuração adicional. O que estou perdendo aqui?Eu acho que
ResponseEntityExceptionHandler
atende às suas necessidades. Um exemplo de código para HTTP 400:Você pode verificar esta postagem
fonte
HttpRequestMethodNotSupportedException
e plug-in o mesmo jar em vários microsserviços, para algum objetivo comercial precisamos responder o nome alternativo do microsserviço na resposta. existe alguma maneira de obter o nome do micro-serviço / nome do controlador subjacente? Eu sei queHandlerMethod
irá fornecer o nome do método java de onde a exceção é originada. Mas aqui, nenhum dos métodos recebeu a solicitação, portantoHandlerMethod
, não será inicializado. Então, existe alguma solução para resolver isso?Embora essa seja uma pergunta antiga, gostaria de compartilhar meus pensamentos sobre isso. Espero que seja útil para alguns de vocês.
Atualmente, estou criando uma API REST que utiliza o Spring Boot 1.5.2.RELEASE com o Spring Framework 4.3.7.RELEASE. Eu uso a abordagem Java Config (em oposição à configuração XML). Além disso, meu projeto usa um mecanismo de manipulação de exceção global usando a
@RestControllerAdvice
anotação (veja mais adiante).Meu projeto tem os mesmos requisitos que o seu: Desejo que minha API REST retorne um
HTTP 404 Not Found
com uma carga JSON correspondente na resposta HTTP ao cliente da API quando tentar enviar uma solicitação para um URL que não existe. No meu caso, a carga útil JSON se parece com esta (que difere claramente do padrão Spring Boot, btw.):Eu finalmente fiz funcionar. Aqui estão as principais tarefas que você precisa executar em breve:
NoHandlerFoundException
seja acionado se os clientes da API chamarem URLS para os quais não existe método manipulador (consulte a Etapa 1 abaixo).ApiError
) que contenha todos os dados que devem ser retornados ao cliente da API (consulte a etapa 2).NoHandlerFoundException
e retorne uma mensagem de erro adequada ao cliente da API (consulte a etapa 3).Ok, agora vamos aos detalhes:
Etapa 1: Configurar application.properties
Eu tive que adicionar as duas configurações a seguir no
application.properties
arquivo do projeto :Isso garante que ele
NoHandlerFoundException
seja lançado nos casos em que um cliente tente acessar uma URL para a qual não exista nenhum método de controlador capaz de lidar com a solicitação.Etapa 2: criar uma classe para erros de API
Fiz uma aula semelhante à sugerida neste artigo no blog de Eugen Paraschiv. Esta classe representa um erro de API. Essas informações são enviadas ao cliente no corpo da resposta HTTP em caso de erro.
Etapa 3: Criar / configurar um manipulador de exceção global
Uso a seguinte classe para lidar com exceções (por simplicidade, removi instruções de importação, código de log e algumas outras partes não relevantes do código):
Etapa 4: escreva um teste
Quero ter certeza de que a API sempre retorna as mensagens de erro corretas para o cliente que está chamando, mesmo em caso de falha. Assim, eu escrevi um teste como este:
A
@ActiveProfiles("dev")
anotação pode ser deixada de fora. Eu o uso apenas enquanto trabalho com perfis diferentes. ORegexMatcher
é um combinador Hamcrest personalizado que eu uso para lidar melhor com os campos de registro de data e hora. Aqui está o código (eu encontrei aqui ):Algumas notas adicionais do meu lado:
@EnableWebMvc
anotação. Isso não foi necessário no meu caso.fonte
E esse código? Eu uso um mapeamento de solicitação de fallback para capturar erros 404.
fonte
Por padrão, o Spring Boot fornece ao json detalhes de erro.
Também funciona para todos os tipos de erros de mapeamento de solicitação. Verifique este artigo http://www.jayway.com/2014/10/19/spring-boot-error-responses/
Se você deseja criar, registre-o no NoSQL. Você pode criar o @ControllerAdvice onde o registraria e, em seguida, lance novamente a exceção. Há um exemplo na documentação https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
fonte
O @RestControllerAdvice é um novo recurso do Spring Framework 4.3 para lidar com a Exceção com RestfulApi por meio de uma solução de interesse transversal:
fonte
Para controladores REST, eu recomendaria usar
Zalando Problem Spring Web
.https://github.com/zalando/problem-spring-web
Se o Spring Boot pretende incorporar alguma configuração automática, esta biblioteca faz mais pelo tratamento de exceções. Você só precisa adicionar a dependência:
E, em seguida, defina uma ou mais características de aconselhamento para suas exceções (ou use as fornecidas por padrão)
Em seguida, você pode definir o conselho do controlador para tratamento de exceções como:
fonte
Para pessoas que desejam responder de acordo com o código de status http, você pode usar o
ErrorController
caminho:O
ResponseBean
aqui é o meu pojo personalizado para resposta.fonte
Solução
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
e@EnableWebMvc @ControllerAdvice
funcionou para mim com o Spring Boot 1.3.1, enquanto não estava funcionando no 1.2.7fonte