Ich versuche, einen großen REST-Serviceserver einzurichten. Wir verwenden Spring Boot 1.2.1 Spring 4.1.5 und Java 8. Unsere Controller implementieren @RestController und die standardmäßigen @ RequestMapping-Annotationen.
Mein Problem ist, dass Spring Boot eine Standardumleitung für Controller-Ausnahmen zu einrichtet /error
. Aus den Dokumenten:
Spring Boot bietet standardmäßig eine / error-Zuordnung, die alle Fehler auf sinnvolle Weise behandelt und als 'globale' Fehlerseite im Servlet-Container registriert ist.
Aus jahrelangen REST-Anwendungen mit Node.js zu schreiben, ist für mich alles andere als sinnvoll. Jede Ausnahme, die ein Service-Endpunkt generiert, sollte in der Antwort zurückgegeben werden. Ich kann nicht verstehen, warum Sie eine Weiterleitung an einen Angular- oder JQuery SPA-Verbraucher senden, der nur nach einer Antwort sucht und bei einer Weiterleitung keine Maßnahmen ergreifen kann oder will.
Ich möchte einen globalen Fehlerhandler einrichten, der jede Ausnahme annehmen kann - entweder absichtlich von einer Anforderungszuordnungsmethode ausgelöst oder von Spring automatisch generiert (404, wenn keine Handlermethode für die Anforderungspfadsignatur gefunden wird), und a zurückgeben Standardformatierte Fehlerantwort (400, 500, 503, 404) an den Client ohne MVC-Umleitungen. Insbesondere nehmen wir den Fehler, protokollieren ihn mit einer UUID bei NoSQL und geben dann den richtigen HTTP-Fehlercode mit der UUID des Protokolleintrags im JSON-Body an den Client zurück.
Die Dokumente waren vage, wie das geht. Es scheint mir, dass Sie entweder Ihre eigene ErrorController- Implementierung erstellen oder ControllerAdvice auf irgendeine Weise verwenden müssen, aber alle Beispiele, die ich gesehen habe, beinhalten immer noch das Weiterleiten der Antwort auf eine Art Fehlerzuordnung, was nicht hilft. Andere Beispiele legen nahe, dass Sie jeden Ausnahmetyp auflisten müssen, den Sie behandeln möchten, anstatt nur "Throwable" aufzulisten und alles abzurufen.
Kann mir jemand sagen, was ich verpasst habe, oder mich in die richtige Richtung weisen, wie dies zu tun ist, ohne die Kette vorzuschlagen, mit der Node.js einfacher umzugehen wäre?
quelle
Antworten:
Neue Antwort (20.04.2016)
Verwenden von Spring Boot 1.3.1.RELEASE
Neuer Schritt 1 - Es ist einfach und weniger aufdringlich, der application.properties die folgenden Eigenschaften hinzuzufügen:
Wenn Sie mit einer vollständigen RESTful-Anwendung arbeiten, ist es sehr wichtig, die automatische Zuordnung statischer Ressourcen zu deaktivieren. Wenn Sie die Standardkonfiguration von Spring Boot für die Verarbeitung statischer Ressourcen verwenden, verarbeitet der Ressourcenhandler die Anforderung (sie wird zuletzt bestellt und / zugeordnet) ** Dies bedeutet, dass alle Anforderungen erfasst werden, die von keinem anderen Handler in der Anwendung verarbeitet wurden. Das Dispatcher-Servlet hat also keine Möglichkeit, eine Ausnahme auszulösen.
Neue Antwort (04.12.2015)
Verwenden von Spring Boot 1.2.7.RELEASE
Neuer Schritt 1 - Ich habe eine viel weniger aufdringliche Möglichkeit gefunden, das Flag "throExceptionIfNoHandlerFound" zu setzen. Ersetzen Sie den DispatcherServlet-Ersetzungscode unten (Schritt 1) durch diesen in Ihrer Anwendungsinitialisierungsklasse:
In diesem Fall setzen wir das Flag für das vorhandene DispatcherServlet, wodurch die automatische Konfiguration durch das Spring Boot-Framework beibehalten wird.
Eine weitere Sache, die ich gefunden habe - die Annotation @EnableWebMvc ist für Spring Boot tödlich. Ja, diese Annotation ermöglicht es beispielsweise, alle Controller-Ausnahmen wie unten beschrieben abzufangen, aber sie beendet auch eine Menge der hilfreichen Autokonfiguration, die Spring Boot normalerweise bereitstellen würde. Verwenden Sie diese Anmerkung mit äußerster Vorsicht, wenn Sie Spring Boot verwenden.
Ursprüngliche Antwort:
Nach viel mehr Recherche und Nachverfolgung der hier veröffentlichten Lösungen (danke für die Hilfe!) Und nicht geringer Laufzeitverfolgung im Spring-Code habe ich endlich eine Konfiguration gefunden, die alle Ausnahmen behandelt (keine Fehler, aber weiterlesen). einschließlich 404s.
Schritt 1 - Weisen Sie SpringBoot an, MVC nicht mehr für Situationen zu verwenden, in denen der Handler nicht gefunden wurde. Wir möchten, dass Spring eine Ausnahme auslöst, anstatt eine auf "/ error" umgeleitete Ansicht an den Client zurückzugeben. Dazu benötigen Sie einen Eintrag in einer Ihrer Konfigurationsklassen:
Der Nachteil dabei ist, dass es das Standard-Dispatcher-Servlet ersetzt. Dies war noch kein Problem für uns, da keine Nebenwirkungen oder Ausführungsprobleme auftraten. Wenn Sie aus anderen Gründen etwas anderes mit dem Dispatcher-Servlet tun, ist dies der richtige Ort, um dies zu tun.
Schritt 2 - Nachdem Spring Boot nun eine Ausnahme auslöst, wenn kein Handler gefunden wird, kann diese Ausnahme mit allen anderen in einem einheitlichen Ausnahmebehandler behandelt werden:
Denken Sie daran, dass ich denke, dass die Annotation "@EnableWebMvc" hier von Bedeutung ist. Es scheint, dass nichts davon ohne es funktioniert. Und das war's - Ihre Spring-Boot-App erkennt jetzt alle Ausnahmen, einschließlich 404s, in der oben genannten Handler-Klasse, und Sie können sie nach Belieben verwenden.
Ein letzter Punkt - es scheint keine Möglichkeit zu geben, dies dazu zu bringen, geworfene Fehler zu fangen. Ich habe eine verrückte Idee, Aspekte zu verwenden, um Fehler zu erkennen und sie in Ausnahmen umzuwandeln, mit denen der obige Code dann umgehen kann, aber ich hatte noch keine Zeit, dies tatsächlich zu implementieren. Hoffe das hilft jemandem.
Alle Kommentare / Korrekturen / Verbesserungen werden geschätzt.
quelle
@ExceptionHandler
Methode, die aufgerufen wird, wenn sie in die@ControllerAdvice
Klasse eingefügt wird, obwohl sie ordnungsgemäß funktionieren, wenn sie in die@RestController
Klasse eingefügt werden.@EnableWebMvc
ist in der@ControllerAdvice
und der@Configuration
(ich habe jede Kombination getestet) Klasse. Irgendeine Idee oder ein funktionierendes Beispiel? // @Andy WilkinsonMit Spring Boot 1.4+ wurden neue coole Klassen für eine einfachere Ausnahmebehandlung hinzugefügt, die beim Entfernen des Boilerplate-Codes helfen.
Für
@RestControllerAdvice
die Ausnahmebehandlung wird ein neues bereitgestellt, es ist eine Kombination aus@ControllerAdvice
und@ResponseBody
. Sie können die@ResponseBody
on-@ExceptionHandler
Methode entfernen , wenn Sie diese neue Anmerkung verwenden.dh
Für die Behandlung von 404-Fehlern war das Hinzufügen von
@EnableWebMvc
Anmerkungen und den folgenden Elementen zu application.properties ausreichend:spring.mvc.throw-exception-if-no-handler-found=true
Sie können die Quellen hier finden und damit spielen:
https://github.com/magiccrafter/spring-boot-exception-handling
quelle
@RestControllerAdvice
ohne zusätzliche Konfiguration zu behandeln. Was fehlt mir hier?Ich denke,
ResponseEntityExceptionHandler
erfüllt Ihre Anforderungen. Ein Beispielcode für HTTP 400:Sie können diesen Beitrag überprüfen
quelle
HttpRequestMethodNotSupportedException
dasselbe JAR in mehreren Mikrodiensten zu verarbeiten und einzufügen. Aus geschäftlichen Gründen müssen wir in der Antwort auf den Namen des Mikrodienstalias antworten. Gibt es eine Möglichkeit, den zugrunde liegenden Namen des Mikrodienstes / Controllers zu erhalten? Ich weißHandlerMethod
, dass der Name der Java-Methode angegeben wird, von dem die Ausnahme stammt. Hier hat jedoch keine der Methoden die Anforderung erhalten und wird daherHandlerMethod
nicht initialisiert. Gibt es also eine Lösung, um dies zu lösen?Obwohl dies eine ältere Frage ist, möchte ich meine Gedanken dazu teilen. Ich hoffe, dass es einigen von Ihnen hilfreich sein wird.
Ich erstelle derzeit eine REST-API, die Spring Boot 1.5.2.RELEASE mit Spring Framework 4.3.7.RELEASE verwendet. Ich verwende den Java Config-Ansatz (im Gegensatz zur XML-Konfiguration). Außerdem verwendet mein Projekt einen globalen Ausnahmebehandlungsmechanismus unter Verwendung der
@RestControllerAdvice
Anmerkung (siehe weiter unten).Für mein Projekt gelten dieselben Anforderungen wie für Ihr Projekt: Ich möchte, dass meine REST-API eine
HTTP 404 Not Found
mit einer zugehörigen JSON-Nutzlast in der HTTP-Antwort an den API-Client zurückgibt, wenn versucht wird, eine Anforderung an eine nicht vorhandene URL zu senden. In meinem Fall sieht die JSON-Nutzlast folgendermaßen aus (was sich übrigens deutlich von der Spring Boot-Standardeinstellung unterscheidet):Ich habe es endlich geschafft. Hier sind die Hauptaufgaben, die Sie kurz erledigen müssen:
NoHandlerFoundException
Stellen Sie sicher, dass das ausgelöst wird, wenn API-Clients URLs aufrufen, für die keine Handlermethode vorhanden ist (siehe Schritt 1 unten).ApiError
), die alle Daten enthält, die an den API-Client zurückgegeben werden sollen (siehe Schritt 2).NoHandlerFoundException
API-Client reagiert und eine entsprechende Fehlermeldung an den API-Client zurückgibt (siehe Schritt 3).Ok, jetzt zu den Details:
Schritt 1: Konfigurieren Sie application.properties
Ich musste der Projektdatei die folgenden zwei Konfigurationseinstellungen hinzufügen
application.properties
:Dies stellt sicher, dass das
NoHandlerFoundException
in Fällen ausgelöst wird, in denen ein Client versucht, auf eine URL zuzugreifen, für die keine Controller-Methode vorhanden ist, die die Anforderung verarbeiten könnte.Schritt 2: Erstellen Sie eine Klasse für API-Fehler
Ich habe eine Klasse ähnlich der in diesem Artikel auf Eugen Paraschivs Blog vorgeschlagenen gemacht. Diese Klasse repräsentiert einen API-Fehler. Diese Informationen werden im Fehlerfall an den Client im HTTP-Antworttext gesendet.
Schritt 3: Erstellen / Konfigurieren eines globalen Ausnahmehandlers
Ich verwende die folgende Klasse, um Ausnahmen zu behandeln (der Einfachheit halber habe ich Importanweisungen, Protokollierungscode und einige andere, nicht relevante Codeteile entfernt):
Schritt 4: Schreiben Sie einen Test
Ich möchte sicherstellen, dass die API auch im Fehlerfall immer die richtigen Fehlermeldungen an den aufrufenden Client zurückgibt. Also habe ich einen Test wie diesen geschrieben:
Die
@ActiveProfiles("dev")
Anmerkung kann weggelassen werden. Ich benutze es nur, wenn ich mit verschiedenen Profilen arbeite. DasRegexMatcher
ist ein Brauch hamcrest Matcher ich besser Felder Zeitstempel Griff verwenden. Hier ist der Code (ich habe ihn hier gefunden ):Einige weitere Anmerkungen von meiner Seite:
@EnableWebMvc
Anmerkung festzulegen. Dies war in meinem Fall nicht notwendig.quelle
Was ist mit diesem Code? Ich verwende eine Fallback-Anforderungszuordnung, um 404-Fehler abzufangen.
quelle
Standardmäßig gibt Spring Boot json Fehlerdetails aus.
Es funktioniert auch für alle Arten von Anforderungszuordnungsfehlern. Überprüfen Sie diesen Artikel http://www.jayway.com/2014/10/19/spring-boot-error-responses/
Wenn Sie erstellen möchten, protokollieren Sie es bei NoSQL. Sie können @ControllerAdvice dort erstellen, wo Sie es protokollieren und dann die Ausnahme erneut auslösen würden. Es gibt ein Beispiel in der Dokumentation https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
quelle
@RestControllerAdvice ist eine neue Funktion von Spring Framework 4.3 zur Behandlung von Ausnahmen mit RestfulApi durch eine übergreifende Lösung:
quelle
Für REST-Controller würde ich die Verwendung empfehlen
Zalando Problem Spring Web
.https://github.com/zalando/problem-spring-web
Wenn Spring Boot eine automatische Konfiguration einbetten möchte, bietet diese Bibliothek mehr für die Ausnahmebehandlung. Sie müssen nur die Abhängigkeit hinzufügen:
Definieren Sie dann ein oder mehrere Beratungsmerkmale für Ihre Ausnahmen (oder verwenden Sie die standardmäßig bereitgestellten).
Anschließend können Sie den Controller-Hinweis für die Ausnahmebehandlung wie folgt definieren:
quelle
Für Personen, die gemäß dem http-Statuscode antworten möchten, können Sie folgende Methoden verwenden
ErrorController
:Das
ResponseBean
hier ist mein benutzerdefiniertes Pojo für die Antwort.quelle
Lösung mit
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
und@EnableWebMvc @ControllerAdvice
arbeitete für mich mit Spring Boot 1.3.1, während nicht auf 1.2.7 arbeitetequelle