首页 > 解决方案 > 尝试使用 Spring Boot 显示自定义错误页面时出现问题

问题描述

我正在维护一个 Spring Boot 应用程序,它使用 Swagger 定义 Rest web 服务并使用 Maven 进行依赖管理。它使用 application.yml 文件作为属性。默认情况下,当发生错误时,任何浏览器都会显示一个 Whitelabel 页面。

应用程序的 pom.xml 中的父级定义如下:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.1.RELEASE</version>
    <relativePath /> <!-- lookup parent from repository -->
</parent>

我在 resources/templates/error 和 resources/public/error 中分​​别为一般错误、404 错误、401 错误和 500 错误创建了 HTML 页面。

之后,我尝试了以下解决方案但没有成功:

  1. 根据https://www.baeldung.com/spring-boot-custom-error-page,我必须按照以下步骤操作:

1.1。从属性文件或主类禁用 Whitelabel 显示。我选择从主要课程中进行:

@SpringBootApplication(scanBasePackages = "com.mycompanyname")
@EnableConfigurationProperties(AppProperties.class)
@EnableAutoConfiguration(exclude = {ErrorMvcAutoConfiguration.class}) // <- Like this!
public class BuySellBackendApplication {

    public static void main(String[] args) {
        SpringApplication.run(BuySellBackendApplication.class, args);
    }
}

1.2. 定义实现ÈrrorController接口的自定义错误控制器。我的定义如下:

@Controller
public class BazaarErrorController implements ErrorController {

    @Override
    public String getErrorPath() {
        return "/custom-error";
    }

    @RequestMapping("/custom-error")
    public String handleError() {
        return "error";
    }
}

1.3. 添加从属性文件定义的错误映射的路径。由于我使用的是 yml 文件,因此属性添加如下:

server:
   error:
      path: "/custom-error"

期望的结果是显示我定义的通用错误页面。但是得到的结果是Tomcat定义的错误页面。此外,Tomcat 的错误页面是从应用程序中使用 Spring Security 的以下类触发的:

public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {

    private static final Logger logger = LoggerFactory.getLogger(RestAuthenticationEntryPoint.class);

    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        logger.error("Responding with unauthorized error. Message - {}", e.getMessage());
        httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getLocalizedMessage());  // <- This line of code
    }
}

在这种情况下,即使使用@RequestBody注解和/或根据获得的 HTTP 错误代码返回不同的页面也是没有用的。

由于公司的要求,我无法删除认证入口点的代码行。此外,它不会将我重定向到我的错误页面,而是打开浏览器的下载对话框。

  1. 根据https://www.logicbig.com/tutorials/spring-framework/spring-boot/servlet-error-handling-outside-mvc.html,我必须定义一个错误页面寄存器。Spring Web 提供了ErrorPageRegistrar执行此操作的接口:
@Bean
public ErrorPageRegistrar errorPageRegistrar() {
    return registry -> {
        ErrorPage e404=new ErrorPage(HttpStatus.NOT_FOUND, "/error/" + HttpStatus.NOT_FOUND.value());
        ErrorPage e401=new ErrorPage(HttpStatus.UNAUTHORIZED, "/error/" + HttpStatus.UNAUTHORIZED.value());
        ErrorPage e500=new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/" + HttpStatus.INTERNAL_SERVER_ERROR.value());
        ErrorPage egeneric=new ErrorPage("/error/error");
        registry.addErrorPages(e401, e404, e500, egeneric);
    };
}

得到的结果与解决方案 1 中覆盖 Authentication 入口点并转到浏览器的下载对话框相同。另外,不清楚ErrorPage构造函数中的 String 参数是物理 HTML 文件还是 servlet 映射。

  1. 使用 Spring 的 ErrorViewResolver 接口定义错误视图解析器,如https://forketyfork.medium.com/how-to-customize-error-page-selection-logic-in-spring-boot-8ea1a6ae122d中所述:
@Configuration
public class ErrorPageConfig {
    private static final Logger logger = LoggerFactory.getLogger(ErrorPageConfig.class);
    @Bean
    public ErrorViewResolver errorViewResolver(ApplicationContext context, ResourceProperties properties){
        ErrorViewResolver resolver=(request, status, model) -> {
            String pathFormat="error/%d";
            String path="";
            switch(status.value()) {
                case 401: case 404: case 500:
                    path=String.format(pathFormat, status.value());
                    break;
                default:
                    logger.info("Codigo de error obtenido {}", status.value());
                    path="error/error";
                    break;
            }
            return new ModelAndView(path);
        };
        return resolver;
    }
}

它给了我与解决方案 2 相同的结果。

我该如何解决这个问题?提前致谢

标签: javaspringspring-boot

解决方案


解决了

解决方法如下:

  1. 不要从属性文件或主类禁用 Whitelabel 显示。

  2. 像解决方案 3 一样完全定义错误视图解析器。

  3. HTML 页面必须在资源/模板中

  4. 您必须将以下依赖项添加到应用程序的 pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

我希望这对需要它的每个人都有帮助。


推荐阅读