Reputation: 71
I'm trying to show custom error pages depending on the HTTP status code. What I have done is implementing Spring's ErrorController
interface in a CustomErrorController
but it seems that Spring Boot is not recognizing it.
I have followed this tutorial to do that: https://www.baeldung.com/spring-boot-custom-error-page (section 3.1).
There I have read that first you need to get rid of the famous Spring's default Whitelabel Error Page. So I did this:
@SpringBootApplication(exclude = { ErrorMvcAutoConfiguration.class })
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
This seems to work since the Whitelabel error page hasn't appeared anymore but now when an error happens the Apache Tomcat error page (that ugly one with the stack trace included) appears instead of mine.
Then I've just implemented my CustomErrorController
like this:
@Controller
@RequestMapping("/error")
public class CustomErrorController implements ErrorController {
@RequestMapping
public String handleError(HttpServletRequest request) {
Integer statusCode = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
if (statusCode != null) {
// Specific error page
return "redirect:/error/" + statusCode;
}
// Global error page
return "error/error";
}
@Override
public String getErrorPath() {
return "/error";
}
@GetMapping("/404")
public String notFoundErrorPage() {
return "error/404";
}
// Other error codes mapping methods
}
I'm using Thymeleaf and my error views are under src/main/resources/views/error
, where every specific error page name follows the recommended format of <error_code>.html
so, for instance, a 404 error would have a 404.html
page associated.
I haven't had any problem with other application views resolving so far. Actually, I have configured my Spring Security to call the /error/403
endpoint if access denied occurs and the error page is shown properly.
Same happens with /error/500
, that is called when an internal server exception occurs since I have also implemented the following @ControllerAdvice @ExceptionHandler
method:
@ControllerAdvice
@Log4j2
public class GlobalDefaultExceptionHandler {
@ExceptionHandler(Exception.class)
public String defaultErrorHandler(Exception exception) throws Exception {
if (AnnotationUtils.findAnnotation(exception.getClass(), ResponseStatus.class) != null) {
throw exception;
}
log.catching(exception);
return "redirect:/error/500";
}
}
So, if each of these endpoints works individually, why if Spring throws an error the handleError
method is not called ever?
Thank you.
Upvotes: 0
Views: 1249
Reputation: 53
Seems as if your GlobalDefaultExceptionHandler
is catching every Exception upfront. That's why handleError
is never called.
Your other endpoints work, cause you are calling them directly - as you describe it.
I would recommend using @ControllerAdvice
to handle specific Exceptions an let your CustomErrorController
implementation handle all not already handled Exceptions. Spring boot will wrap them inside NestedServletException
with Http Status 500. You can get the root cause inside handleError
with:
Object exception = request.getAttribute("javax.servlet.error.exception");
if (String.valueOf(exception) != null) {
log.info("Nested Exception: " + String.valueOf(exception));
}
Check those answers for further information on ordering and the error work flow in spring boot:
spring boot error handling flow
Upvotes: 1