J'essaye de mettre en place un serveur de services REST à grande échelle. Nous utilisons Spring Boot 1.2.1 Spring 4.1.5 et Java 8. Nos contrôleurs implémentent @RestController et les annotations standard @RequestMapping.
Mon problème est que Spring Boot configure une redirection par défaut pour les exceptions de contrôleur à /error
. À partir de la documentation:
Spring Boot fournit un mappage / error par défaut qui gère toutes les erreurs de manière sensible, et il est enregistré en tant que page d'erreur «globale» dans le conteneur de servlet.
Venant d'années à écrire des applications REST avec Node.js, c'est pour moi tout sauf raisonnable. Toute exception générée par un point de terminaison de service doit renvoyer dans la réponse. Je ne peux pas comprendre pourquoi vous enverriez une redirection vers ce qui est probablement un consommateur Angular ou JQuery SPA qui recherche uniquement une réponse et ne peut ou ne prendra aucune action sur une redirection.
Ce que je veux faire, c'est configurer un gestionnaire d'erreurs global qui peut prendre n'importe quelle exception - soit délibérément levé à partir d'une méthode de mappage de demande, soit généré automatiquement par Spring (404 si aucune méthode de gestionnaire n'est trouvée pour la signature du chemin de la demande), et retourner un réponse d'erreur formatée standard (400, 500, 503, 404) au client sans aucune redirection MVC. Plus précisément, nous allons prendre l'erreur, la consigner sur NoSQL avec un UUID, puis retourner au client le bon code d'erreur HTTP avec l'UUID de l'entrée de journal dans le corps JSON.
Les documents ont été vagues sur la façon de procéder. Il me semble que vous devez créer votre propre implémentation ErrorController ou utiliser ControllerAdvice d'une manière ou d'une autre, mais tous les exemples que j'ai vus incluent toujours la transmission de la réponse à une sorte de mappage d'erreur, ce qui n'aide pas. D'autres exemples suggèrent que vous devez lister tous les types d'exceptions que vous souhaitez gérer au lieu de simplement lister "Throwable" et obtenir tout.
Quelqu'un peut-il me dire ce que j'ai manqué ou m'indiquer la bonne direction sur la façon de le faire sans suggérer la chaîne avec laquelle Node.js serait plus facile à gérer?
la source
Réponses:
Nouvelle réponse (2016-04-20)
Utilisation de Spring Boot 1.3.1.RELEASE
Nouvelle étape 1 - Il est facile et moins intrusif d'ajouter les propriétés suivantes à l'application.properties:
Si vous travaillez avec une application RESTful complète, il est très important de désactiver le mappage automatique des ressources statiques car si vous utilisez la configuration par défaut de Spring Boot pour gérer les ressources statiques, le gestionnaire de ressources traitera la demande (elle est commandée en dernier et mappée à / ** ce qui signifie qu'il récupère toutes les demandes qui n'ont été gérées par aucun autre gestionnaire de l'application), de sorte que le servlet du répartiteur n'a pas la possibilité de lever une exception.
Nouvelle réponse (2015-12-04)
Utilisation de Spring Boot 1.2.7.RELEASE
Nouvelle étape 1 - J'ai trouvé une manière beaucoup moins intrusive de définir le drapeau "throExceptionIfNoHandlerFound". Remplacez le code de remplacement DispatcherServlet ci-dessous (étape 1) par celui-ci dans la classe d'initialisation de votre application:
Dans ce cas, nous définissons l'indicateur sur le DispatcherServlet existant, qui préserve toute configuration automatique par le framework Spring Boot.
Une dernière chose que j'ai trouvée - l'annotation @EnableWebMvc est mortelle pour Spring Boot. Oui, cette annotation permet, par exemple, de pouvoir intercepter toutes les exceptions du contrôleur comme décrit ci-dessous, mais elle élimine également BEAUCOUP de la configuration automatique utile que Spring Boot fournirait normalement. Utilisez cette annotation avec une extrême prudence lorsque vous utilisez Spring Boot.
Réponse originale:
Après beaucoup plus de recherches et de suivi des solutions publiées ici (merci pour l'aide!) Et pas une petite quantité de traçage d'exécution dans le code Spring, j'ai finalement trouvé une configuration qui gérera toutes les exceptions (pas les erreurs, mais lisez la suite) dont 404.
Étape 1 - dites à SpringBoot d'arrêter d'utiliser MVC pour les situations de «gestionnaire introuvable». Nous voulons que Spring lève une exception au lieu de renvoyer au client une redirection de vue vers "/ error". Pour ce faire, vous devez avoir une entrée dans l'une de vos classes de configuration:
L'inconvénient est qu'il remplace le servlet du répartiteur par défaut. Cela n'a pas encore été un problème pour nous, sans effets secondaires ni problèmes d'exécution. Si vous voulez faire autre chose avec le servlet du répartiteur pour d'autres raisons, c'est ici que vous devez le faire.
Étape 2 - Maintenant que spring boot lèvera une exception lorsqu'aucun gestionnaire n'est trouvé, cette exception peut être gérée avec n'importe quelle autre dans un gestionnaire d'exceptions unifié:
Gardez à l'esprit que je pense que l'annotation "@EnableWebMvc" est importante ici. Il semble que rien de tout cela ne fonctionne sans lui. Et c'est tout - votre application Spring Boot détecte désormais toutes les exceptions, y compris les 404, dans la classe de gestionnaire ci-dessus et vous pouvez les utiliser à votre guise.
Un dernier point - il ne semble pas y avoir de moyen d'obtenir cela pour attraper les erreurs lancées. J'ai une idée farfelue d'utiliser des aspects pour détecter les erreurs et les transformer en exceptions que le code ci-dessus peut ensuite traiter, mais je n'ai pas encore eu le temps d'essayer de l'implémenter. J'espère que cela aide quelqu'un.
Tous les commentaires / corrections / améliorations seront appréciés.
la source
@ExceptionHandler
méthode appelée lorsque je la place dans la@ControllerAdvice
classe bien qu'elles fonctionnent correctement si elles sont placées dans la@RestController
classe.@EnableWebMvc
est sur la classe@ControllerAdvice
et@Configuration
(j'ai testé chaque combinaison). Une idée ou un exemple concret? // @Andy WilkinsonAvec Spring Boot 1.4+, de nouvelles classes cool pour faciliter la gestion des exceptions ont été ajoutées, ce qui aide à supprimer le code standard.
Un nouveau
@RestControllerAdvice
est fourni pour la gestion des exceptions, c'est une combinaison de@ControllerAdvice
et@ResponseBody
. Vous pouvez supprimer le@ResponseBody
sur la@ExceptionHandler
méthode lorsque vous utilisez cette nouvelle annotation.c'est à dire
Pour gérer les erreurs 404, l'ajout d'
@EnableWebMvc
annotation et de ce qui suit à application.properties était suffisant:spring.mvc.throw-exception-if-no-handler-found=true
Vous pouvez trouver et jouer avec les sources ici:
https://github.com/magiccrafter/spring-boot-exception-handling
la source
@RestControllerAdvice
sans configuration supplémentaire. Qu'est-ce que j'oublie ici?Je pense que
ResponseEntityExceptionHandler
répond à vos exigences. Un exemple de code pour HTTP 400:Vous pouvez consulter ce post
la source
HttpRequestMethodNotSupportedException
et installer le même fichier jar dans plusieurs micro-services, dans certains cas, nous devons répondre au nom d'alias du micro-service dans la réponse. existe-t-il un moyen d'obtenir le nom du micro-service / le nom du contrôleur sous-jacent? Je sais que jeHandlerMethod
fournirai le nom de la méthode java d'où l'exception est originaire. Mais ici, aucune des méthodes n'a reçu la demande, doncHandlerMethod
ne sera pas initialisée. Alors, y a-t-il une solution pour résoudre ce problème?Bien que ce soit une question plus ancienne, je voudrais partager mes réflexions à ce sujet. J'espère que cela sera utile à certains d'entre vous.
Je construis actuellement une API REST qui utilise Spring Boot 1.5.2.RELEASE avec Spring Framework 4.3.7.RELEASE. J'utilise l'approche Java Config (par opposition à la configuration XML). De plus, mon projet utilise un mécanisme global de gestion des exceptions utilisant l'
@RestControllerAdvice
annotation (voir plus loin ci-dessous).Mon projet a les mêmes exigences que le vôtre: je veux que mon API REST renvoie un
HTTP 404 Not Found
avec une charge utile JSON qui l'accompagne dans la réponse HTTP au client API lorsqu'il tente d'envoyer une requête à une URL qui n'existe pas. Dans mon cas, la charge utile JSON ressemble à ceci (qui diffère clairement de la valeur par défaut de Spring Boot, btw.):Je l'ai finalement fait fonctionner. Voici les principales tâches que vous devez effectuer en bref:
NoHandlerFoundException
est levé si les clients API appellent des URL pour lesquelles aucune méthode de gestionnaire n'existe (voir l'étape 1 ci-dessous).ApiError
) qui contient toutes les données qui doivent être renvoyées au client API (voir étape 2).NoHandlerFoundException
et renvoie un message d'erreur approprié au client API (voir étape 3).Ok, maintenant aux détails:
Étape 1: Configurez application.properties
J'ai dû ajouter les deux paramètres de configuration suivants au
application.properties
fichier du projet :Cela garantit que le
NoHandlerFoundException
est levé dans les cas où un client tente d'accéder à une URL pour laquelle il n'existe aucune méthode de contrôleur qui serait en mesure de gérer la demande.Étape 2: créer une classe pour les erreurs d'API
J'ai fait un cours similaire à celui suggéré dans cet article sur le blog d'Eugen Paraschiv. Cette classe représente une erreur d'API. Ces informations sont envoyées au client dans le corps de la réponse HTTP en cas d'erreur.
Étape 3: créer / configurer un gestionnaire d'exceptions global
J'utilise la classe suivante pour gérer les exceptions (pour plus de simplicité, j'ai supprimé les instructions d'importation, le code de journalisation et d'autres morceaux de code non pertinents):
Étape 4: rédigez un test
Je veux m'assurer que l'API renvoie toujours les bons messages d'erreur au client appelant, même en cas d'échec. Ainsi, j'ai écrit un test comme celui-ci:
L'
@ActiveProfiles("dev")
annotation peut être laissée de côté. Je l'utilise uniquement car je travaille avec différents profils. IlRegexMatcher
s'agit d'un matcher Hamcrest personnalisé que j'utilise pour mieux gérer les champs d'horodatage. Voici le code (je l'ai trouvé ici ):Quelques notes supplémentaires de mon côté:
@EnableWebMvc
annotation. Ce n'était pas nécessaire dans mon cas.la source
Et ce code? J'utilise un mappage de demande de secours pour attraper les erreurs 404.
la source
Par défaut, Spring Boot donne à json les détails de l'erreur.
Cela fonctionne également pour tous les types d'erreurs de mappage de demande. Consultez cet article http://www.jayway.com/2014/10/19/spring-boot-error-responses/
Si vous souhaitez créer un journal sur NoSQL. Vous pouvez créer @ControllerAdvice où vous le consigneriez, puis relancer l'exception. Il y a un exemple dans la documentation https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
la source
@RestControllerAdvice est une nouvelle fonctionnalité de Spring Framework 4.3 pour gérer l'exception avec RestfulApi par une solution de préoccupation transversale:
la source
Pour les contrôleurs REST, je recommanderais d'utiliser
Zalando Problem Spring Web
.https://github.com/zalando/problem-spring-web
Si Spring Boot vise à intégrer une configuration automatique, cette bibliothèque en fait plus pour la gestion des exceptions. Il vous suffit d'ajouter la dépendance:
Et puis définissez un ou plusieurs traits de conseil pour vos exceptions (ou utilisez ceux fournis par défaut)
Ensuite, vous pouvez définir le conseil du contrôleur pour la gestion des exceptions comme:
la source
Pour les personnes qui souhaitent répondre en fonction du code d'état http, vous pouvez utiliser la
ErrorController
méthode:Le
ResponseBean
voici mon pojo personnalisé pour la réponse.la source
Solution avec
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
et a@EnableWebMvc @ControllerAdvice
fonctionné pour moi avec Spring Boot 1.3.1, alors que ne fonctionnait pas sur 1.2.7la source