Chcę użyć ogólnego sposobu zarządzania kodami błędów 5xx, powiedzmy konkretnie w przypadku, gdy db nie działa w całej mojej wiosennej aplikacji. Chcę mieć ładny plik JSON o błędzie zamiast śladu stosu.
Dla kontrolerów mam @ControllerAdvice
klasę dla różnych wyjątków i to również wychwytuje przypadek, że db zatrzymuje się w środku żądania. Ale to nie wszystko. Zdarza mi się również mieć niestandardowe CorsFilter
rozszerzenie OncePerRequestFilter
i kiedy dzwonię, doFilter
otrzymuję CannotGetJdbcConnectionException
i nie będzie zarządzany przez @ControllerAdvice
. Przeczytałem kilka rzeczy w Internecie, które tylko wprawiły mnie w zakłopotanie.
Mam więc dużo pytań:
- Czy muszę zaimplementować niestandardowy filtr? Znalazłem,
ExceptionTranslationFilter
ale to tylko obsługujeAuthenticationException
lubAccessDeniedException
. - Myślałem o wdrożeniu własnego
HandlerExceptionResolver
, ale to wzbudziło we mnie wątpliwości, nie mam żadnego niestandardowego wyjątku do zarządzania, musi być bardziej oczywisty sposób niż ten. Próbowałem też dodać try / catch i wywołać implementacjęHandlerExceptionResolver
(powinno być wystarczająco dobre, mój wyjątek nie jest niczym specjalnym), ale to nie zwraca niczego w odpowiedzi, otrzymuję status 200 i puste ciało.
Czy jest jakiś dobry sposób, aby sobie z tym poradzić? Dzięki
java
spring
spring-security
kopelitsa
źródło
źródło
Odpowiedzi:
Oto co zrobiłem:
Czytałem podstawowe informacje na temat filtrów tutaj i zorientowali się, że trzeba utworzyć własny filtr, który będzie pierwszym w łańcuchu filtrów i będzie mieć zaczep Spróbuj złapać wszystkie wyjątki uruchomieniowe, które mogą tam wystąpić. Następnie muszę ręcznie utworzyć plik json i umieścić go w odpowiedzi.
Oto mój niestandardowy filtr:
Następnie dodałem go w pliku web.xml przed rozszerzeniem
CorsFilter
. I to działa!źródło
Chciałem przedstawić rozwiązanie oparte na odpowiedzi @kopelitsa . Główne różnice to:
HandlerExceptionResolver
.Najpierw musisz upewnić się, że masz klasę, która obsługuje wyjątki występujące w zwykłym RestController / Controller (klasa z adnotacją
@RestControllerAdvice
lub@ControllerAdvice
i metody z adnotacjami@ExceptionHandler
). To obsługuje wyjątki występujące w kontrolerze. Oto przykład użycia RestControllerAdvice:Aby ponownie użyć tego zachowania w łańcuchu filtrów Spring Security, musisz zdefiniować filtr i podłączyć go do konfiguracji zabezpieczeń. Filtr musi przekierować wyjątek do wyżej zdefiniowanej obsługi wyjątków. Oto przykład:
Utworzony filtr należy następnie dodać do SecurityConfiguration. Musisz podłączyć go do łańcucha bardzo wcześnie, ponieważ wszystkie poprzednie wyjątki filtru nie zostaną przechwycone. W moim przypadku rozsądne było dodanie go przed
LogoutFilter
. Zobacz domyślny łańcuch filtrów i jego kolejność w oficjalnych dokumentach . Oto przykład:źródło
Sam natknąłem się na ten problem i wykonałem poniższe kroki, aby ponownie użyć mojego,
ExceptionController
który jest oznaczony adnotacją@ControllerAdvise
doExceptions
wrzucenia do zarejestrowanego filtru.Jest oczywiście wiele sposobów obsługi wyjątków, ale w moim przypadku chciałem, aby wyjątek był obsługiwany przez mój,
ExceptionController
ponieważ jestem uparty, a także dlatego, że nie chcę kopiować / wklejać tego samego kodu (tj. Mam trochę przetwarzania / logowania kod wExceptionController
). Chciałbym zwrócić pięknąJSON
odpowiedź, tak jak pozostałe wyjątki wyrzucone nie z filtra.W każdym razie udało mi się wykorzystać moje
ExceptionHandler
i musiałem zrobić trochę więcej, jak pokazano poniżej w krokach:Kroki
@ControllerAdvise
np. MyExceptionControllerPrzykładowy kod
A teraz przykładowy kontroler sprężyny, który obsługuje
Exception
w normalnych przypadkach (tj. Wyjątki, które zwykle nie są zgłaszane na poziomie filtru, ten, którego chcemy użyć do wyjątków rzucanych w filtrze)Udostępnianie rozwiązania tym, którzy chcą użyć
ExceptionController
doExceptions
wrzucenia do filtra.źródło
@Component
klasy i użyj jej w filtrze i w Administratora.answer
tym, jest to jeden ze sposobów! Nie twierdziłem, że to najlepszy sposób. Dziękuję za podzielenie się troską @psv Jestem pewien, że społeczność doceni rozwiązanie, o którym myślisz :)Oto, co zrobiłem, opierając się na połączeniu powyższych odpowiedzi ... Mieliśmy już
GlobalExceptionHandler
adnotację@ControllerAdvice
i chciałem również znaleźć sposób na ponowne użycie tego kodu do obsługi wyjątków pochodzących z filtrów.Najprostszym rozwiązaniem, jakie udało mi się znaleźć, było pozostawienie obsługi wyjątków w spokoju i zaimplementowanie kontrolera błędów w następujący sposób:
Tak więc wszelkie błędy spowodowane przez wyjątki najpierw przechodzą przez program
ErrorController
i są przekierowywane do programu obsługi wyjątków przez ponowne zgłoszenie ich z@Controller
kontekstu, podczas gdy wszelkie inne błędy (nie spowodowane bezpośrednio przez wyjątek) przechodząErrorController
bez modyfikacji.Jakieś powody, dla których to właściwie zły pomysł?
źródło
@Override public String getErrorPath() { return null; }
Jeśli chcesz uzyskać ogólny sposób, możesz zdefiniować stronę błędu w web.xml:
I dodaj mapowanie w Spring MVC:
źródło
To jest moje rozwiązanie przez nadpisanie domyślnej obsługi Spring Boot / Error
źródło
Tylko w celu uzupełnienia innych dobrych odpowiedzi, ponieważ zbyt niedawno chciałem pojedynczy składnik obsługi błędów / wyjątków w prostej aplikacji SpringBoot zawierającej filtry, które mogą generować wyjątki, z innymi wyjątkami potencjalnie wyrzucanymi z metod kontrolera.
Na szczęście wydaje się, że nic nie stoi na przeszkodzie, aby połączyć porady dotyczące kontrolera z zastąpieniem domyślnej obsługi błędów Springa w celu zapewnienia spójnych ładunków odpowiedzi, umożliwienia udostępniania logiki, sprawdzania wyjątków z filtrów, pułapek wyjątków zgłaszanych przez usługi itp.
Na przykład
źródło
Jeśli chcesz przetestować stan aplikacji iw przypadku problemu zwrócić błąd HTTP, proponuję filtr. Poniższy filtr obsługuje wszystkie żądania HTTP. Najkrótsze rozwiązanie w Spring Boot z filtrem javax.
W realizacji mogą być różne warunki. W moim przypadku applicationManager sprawdza, czy aplikacja jest gotowa.
źródło
Po zapoznaniu się z różnymi metodami sugerowanymi w powyższych odpowiedziach zdecydowałem się obsłużyć wyjątki uwierzytelniania za pomocą niestandardowego filtru. Byłem w stanie obsłużyć status odpowiedzi i kody za pomocą klasy odpowiedzi na błąd przy użyciu następującej metody.
Utworzyłem niestandardowy filtr i zmodyfikowałem konfigurację zabezpieczeń za pomocą metody addFilterAfter i dodałem po klasie CorsFilter.
SecurityConfig klasa
Klasa ErrorResponse
źródło
Możesz użyć następującej metody wewnątrz bloku catch:
Zwróć uwagę, że możesz użyć dowolnego kodu HttpStatus i niestandardowej wiadomości.
źródło
To dziwne, ponieważ @ControllerAdvice powinno działać, czy wychwytujesz prawidłowy wyjątek?
Spróbuj też złapać ten wyjątek w CorsFilter i wysłać błąd 500, coś takiego
źródło
Filter
może nie zostać złapany,@ControllerAdvice
ponieważ może nie sięgaćDispatcherServlet
.Nie musisz w tym celu tworzyć niestandardowego filtru. Rozwiązaliśmy to, tworząc niestandardowe wyjątki, które rozszerzają ServletException (który jest wyrzucany z metody doFilter, pokazanej w deklaracji). Są one następnie przechwytywane i obsługiwane przez naszą globalną procedurę obsługi błędów.
edycja: gramatyka
źródło