Estoy tratando de configurar un servidor de servicios REST a gran escala. Estamos utilizando Spring Boot 1.2.1 Spring 4.1.5 y Java 8. Nuestros controladores están implementando @RestController y las anotaciones estándar @RequestMapping.
Mi problema es que Spring Boot configura una redirección predeterminada para las excepciones del controlador /error
. De los documentos:
Spring Boot proporciona una asignación / error por defecto que maneja todos los errores de una manera sensata, y está registrada como una página de error 'global' en el contenedor de servlets.
Viniendo de años escribiendo aplicaciones REST con Node.js, esto es, para mí, todo menos sensato. Cualquier excepción que genere un punto final de servicio debería volver en la respuesta. No puedo entender por qué enviaría una redirección a lo que probablemente sea un consumidor de Angular o JQuery SPA que solo está buscando una respuesta y no puede o no tomará ninguna acción en una redirección.
Lo que quiero hacer es configurar un controlador de errores global que pueda tomar cualquier excepción, ya sea arrojado intencionalmente desde un método de mapeo de solicitud o generado automáticamente por Spring (404 si no se encuentra ningún método de controlador para la firma de ruta de solicitud), y devolver un respuesta de error con formato estándar (400, 500, 503, 404) al cliente sin ningún redireccionamiento MVC. Específicamente, vamos a tomar el error, registrarlo en NoSQL con un UUID, luego devolver al cliente el código de error HTTP correcto con el UUID de la entrada de registro en el cuerpo JSON.
Los documentos han sido vagos sobre cómo hacer esto. Me parece que tiene que crear su propia implementación de ErrorController o usar ControllerAdvice de alguna manera, pero todos los ejemplos que he visto todavía incluyen reenviar la respuesta a algún tipo de mapeo de errores, lo que no ayuda. Otros ejemplos sugieren que tendría que enumerar todos los tipos de Excepción que desea manejar en lugar de simplemente enumerar "Throwable" y obtener todo.
¿Alguien puede decirme lo que me perdí o señalarme en la dirección correcta cómo hacerlo sin sugerir la cadena con la que Node.js sería más fácil de tratar?
fuente
Respuestas:
Nueva respuesta (20/04/2016)
Usando Spring Boot 1.3.1.RELEASE
Nuevo paso 1: es fácil y menos intrusivo agregar las siguientes propiedades a la aplicación.
Si trabaja con una aplicación RESTful completa, es muy importante deshabilitar la asignación automática de recursos estáticos, ya que si está utilizando la configuración predeterminada de Spring Boot para manejar recursos estáticos, el controlador de recursos manejará la solicitud (se ordena al final y se asigna a / ** lo que significa que recoge cualquier solicitud que no haya sido manejada por ningún otro controlador en la aplicación) para que el servlet del despachador no tenga la oportunidad de lanzar una excepción.
Nueva respuesta (04/12/2015)
Usando Spring Boot 1.2.7.RELEASE
Nuevo paso 1: encontré una forma mucho menos intrusiva de configurar el indicador "throExceptionIfNoHandlerFound". Reemplace el código de reemplazo de DispatcherServlet a continuación (Paso 1) con esto en la clase de inicialización de su aplicación:
En este caso, estamos configurando el indicador en el DispatcherServlet existente, que conserva cualquier configuración automática por parte del marco Spring Boot.
Una cosa más que he encontrado: la anotación @EnableWebMvc es mortal para Spring Boot. Sí, esa anotación permite cosas como poder capturar todas las excepciones del controlador como se describe a continuación, pero también elimina MUCHA de la útil configuración automática que Spring Boot proporcionaría normalmente. Use esa anotación con extrema precaución cuando use Spring Boot.
Respuesta original
Después de mucha más investigación y seguimiento de las soluciones publicadas aquí (¡gracias por la ayuda!) Y una pequeña cantidad de tiempo de ejecución en el código Spring, finalmente encontré una configuración que manejará todas las Excepciones (no Errores, pero sigue leyendo) incluyendo 404s.
Paso 1: dígale a SpringBoot que deje de usar MVC para situaciones de "controlador no encontrado". Queremos que Spring arroje una excepción en lugar de devolver al cliente una vista redirigida a "/ error". Para hacer esto, debe tener una entrada en una de sus clases de configuración:
La desventaja de esto es que reemplaza el servlet del despachador predeterminado. Esto no ha sido un problema para nosotros todavía, sin efectos secundarios ni problemas de ejecución. Si va a hacer algo más con el servlet del despachador por otros motivos, este es el lugar para hacerlo.
Paso 2: ahora que el arranque de primavera generará una excepción cuando no se encuentre un controlador, esa excepción se puede manejar con cualquier otro en un controlador de excepciones unificado:
Tenga en cuenta que creo que la anotación "@EnableWebMvc" es importante aquí. Parece que nada de esto funciona sin él. Y eso es todo: su aplicación de arranque Spring ahora detectará todas las excepciones, incluidas las 404, en la clase de controlador anterior y puede hacerlas como desee.
Un último punto: no parece haber una manera de hacer que esto atrape los errores arrojados. Tengo una extraña idea de usar aspectos para detectar errores y convertirlos en Excepciones con las que el código anterior puede lidiar, pero aún no he tenido tiempo de intentar implementarlo. Espero que esto ayude a alguien.
Cualquier comentario / corrección / mejora será apreciado.
fuente
@ExceptionHandler
método al colocarlo en la@ControllerAdvice
clase, aunque funcionan correctamente si se colocan en la@RestController
clase.@EnableWebMvc
está en la clase@ControllerAdvice
y@Configuration
(probé cada combinación). ¿Alguna idea o ejemplo de trabajo? // @Andy WilkinsonCon Spring Boot 1.4+ se agregaron nuevas clases interesantes para un manejo de excepciones más fácil que ayuda a eliminar el código repetitivo.
Se
@RestControllerAdvice
proporciona una nueva para el manejo de excepciones, es una combinación de@ControllerAdvice
y@ResponseBody
. Se puede quitar el@ResponseBody
en el@ExceptionHandler
método cuando se utiliza esta nueva anotación.es decir
Para manejar errores 404, agregar
@EnableWebMvc
anotaciones y lo siguiente a application.properties fue suficiente:spring.mvc.throw-exception-if-no-handler-found=true
Puedes encontrar y jugar con las fuentes aquí:
https://github.com/magiccrafter/spring-boot-exception-handling
fuente
@RestControllerAdvice
sin configuración adicional. ¿Que me estoy perdiendo aqui?Creo que
ResponseEntityExceptionHandler
cumple con tus requisitos. Una pieza de código de muestra para HTTP 400:Puedes consultar esta publicación
fuente
HttpRequestMethodNotSupportedException
y conectar el mismo jar en múltiples microservicios, para algún propósito comercial necesitamos responder el nombre del alias del micro servicio en la respuesta. ¿Hay alguna manera de que podamos obtener el nombre del micro servicio / nombre del controlador subyacente? SéHandlerMethod
que proporcionará el nombre del método Java desde donde se origina la excepción. Pero aquí, ninguno de los métodos recibió la solicitud, porHandlerMethod
lo tanto , no se inicializará. Entonces, ¿hay alguna solución para resolver esto?Aunque esta es una pregunta anterior, me gustaría compartir mis pensamientos al respecto. Espero que sea útil para algunos de ustedes.
Actualmente estoy construyendo una API REST que hace uso de Spring Boot 1.5.2.RELEASE con Spring Framework 4.3.7.RELEASE. Yo uso el enfoque de Java Config (a diferencia de la configuración XML). Además, mi proyecto usa un mecanismo global de manejo de excepciones usando la
@RestControllerAdvice
anotación (ver más adelante).Mi proyecto tiene los mismos requisitos que el suyo: quiero que mi API REST devuelva un
HTTP 404 Not Found
mensaje con una carga útil JSON adjunta en la respuesta HTTP al cliente API cuando intenta enviar una solicitud a una URL que no existe. En mi caso, la carga útil de JSON se ve así (que claramente difiere del valor predeterminado de Spring Boot, por cierto):Finalmente lo hice funcionar. Estas son las tareas principales que debe hacer en resumen:
NoHandlerFoundException
se lance si los clientes API llaman a URLS para las cuales no existe ningún método de controlador (consulte el Paso 1 a continuación).ApiError
) que contenga todos los datos que deben devolverse al cliente API (consulte el paso 2).NoHandlerFoundException
y devuelva un mensaje de error adecuado al cliente API (consulte el paso 3).Ok, ahora a los detalles:
Paso 1: Configurar application.properties
Tuve que agregar las siguientes dos configuraciones al
application.properties
archivo del proyecto :Esto garantiza que
NoHandlerFoundException
se lance en los casos en que un cliente intente acceder a una URL para la cual no existe un método de controlador que pueda manejar la solicitud.Paso 2: crear una clase para errores de API
Hice una clase similar a la sugerida en este artículo en el blog de Eugen Paraschiv. Esta clase representa un error de API. Esta información se envía al cliente en el cuerpo de respuesta HTTP en caso de error.
Paso 3: crear / configurar un controlador de excepción global
Utilizo la siguiente clase para manejar excepciones (por simplicidad, he eliminado las declaraciones de importación, el código de registro y algunos otros fragmentos de código no relevantes):
Paso 4: escribe una prueba
Quiero asegurarme de que la API siempre devuelve los mensajes de error correctos al cliente que realiza la llamada, incluso en caso de falla. Por lo tanto, escribí una prueba como esta:
La
@ActiveProfiles("dev")
anotación se puede dejar de lado. Lo uso solo cuando trabajo con diferentes perfiles. ElRegexMatcher
es un emparejador Hamcrest personalizado que uso para manejar mejor los campos de marca de tiempo. Aquí está el código (lo encontré aquí ):Algunas notas adicionales de mi parte:
@EnableWebMvc
anotación. Esto no fue necesario en mi caso.fuente
¿Qué hay de este código? Utilizo una asignación de solicitud de reserva para detectar errores 404.
fuente
Por defecto, Spring Boot proporciona json con detalles de error.
También funciona para todo tipo de errores de mapeo de solicitudes. Consulte este artículo http://www.jayway.com/2014/10/19/spring-boot-error-responses/
Si desea crear, inicie sesión en NoSQL. Puede crear @ControllerAdvice donde lo registraría y luego volver a lanzar la excepción. Hay un ejemplo en la documentación https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
fuente
@RestControllerAdvice es una nueva característica de Spring Framework 4.3 para manejar Exception with RestfulApi mediante una solución de preocupación transversal:
fuente
Para los controladores REST, recomendaría usar
Zalando Problem Spring Web
.https://github.com/zalando/problem-spring-web
Si Spring Boot tiene como objetivo incrustar alguna configuración automática, esta biblioteca hace más para el manejo de excepciones. Solo necesita agregar la dependencia:
Y luego defina uno o más rasgos de asesoramiento para sus excepciones (o use los que se proporcionan por defecto)
Luego puede definir el consejo del controlador para el manejo de excepciones como:
fuente
Para las personas que desean responder de acuerdo con el código de estado http, puede usar la
ErrorController
forma:La
ResponseBean
Aquí está mi POJO personalizado para la respuesta.fuente
Solución
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
y@EnableWebMvc @ControllerAdvice
funcionó para mí con Spring Boot 1.3.1, mientras no funcionaba en 1.2.7fuente