Elliot RG
Elliot RG

Reputation: 71

Spring Boot doesn't show error pages implementing a custom ErrorController

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

Answers (1)

omonsees
omonsees

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:

order

spring boot error handling flow

Upvotes: 1

Related Questions