如何在 Spring Boot 应用程序的错误页面上屏蔽 Apache 版本?

Posted

技术标签:

【中文标题】如何在 Spring Boot 应用程序的错误页面上屏蔽 Apache 版本?【英文标题】:How to mask Apache Version on Error Page of Spring Boot application? 【发布时间】:2022-01-08 00:49:00 【问题描述】:

我有一个带有嵌入式 tomcat 的 spring boot 应用程序,每当发生服务器错误时,我想在错误页面上隐藏 apache tomcat 版本。

据我所知;最知名的解决方案是将 server.properties 添加到 web.xml 或压缩 catalina jar。

由于应用没有web.xml,所以想不通隐藏tomcat版本。

Tomcat 服务器属性已更改如下,但均无效。

server.error.include-stacktrace=never

server.error.whitelabel.enabled=false

春季开机版本:2.5.4

请参考图片。

谢谢!

【问题讨论】:

这能回答你的问题吗? How to change Apache Tomcat default error page values? 由于强制创建自定义错误页面并且只处理错误响应代码,这不是我的答案,谢谢。 请添加完整的屏幕截图而不是 sn-p,并指定您使用的 Spring Boot 哪个版本 我编辑了我的问题并添加了完整的屏幕截图,谢谢。 stacktrace 看起来与 Spring Boot 或嵌入式 tomcat 无关。因此,尝试从应用程序中管理外部 tomcat 显然是行不通的。 【参考方案1】:

对于嵌入式 tomcat,我找到了覆盖错误报告阀的配置

现在响应没有tomcat版本。


var host = (StandardHost) tomcat.getHost();

var errorReportValve = new org.apache.catalina.valves.ErrorReportValve();
errorReportValve.setShowReport(false);
errorReportValve.setShowServerInfo(false);
host.addValve(errorReportValve); 


【讨论】:

【参考方案2】:

可能与以下相同的问题:

Allow custom ErrorReportValve to be used with Tomcat and provide whitelabel version #21257
import java.io.IOException;
import java.io.Writer;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ErrorReportValve;
import org.apache.coyote.ActionCode;
import org.apache.tomcat.util.ExceptionUtils;

public class CustomErrorReportValve extends ErrorReportValve 

    // Create a simple logger
    Logger log = Logger.getLogger(CustomErrorReportValve.class.getName());

    @Override
    protected void report(final Request request, final Response response, final Throwable throwable) 
        // ref: ErrorReportValve implementation

        final int statusCode = response.getStatus();

        // Do nothing on a 1xx, 2xx and 3xx status
        // Do nothing if anything has been written already
        // Do nothing if the response hasn't been explicitly marked as in error
        //    and that error has not been reported.
        if (statusCode < 400 || response.getContentWritten() > 0 || !response.setErrorReported()) 
            return;
        

        // If an error has occurred that prevents further I/O, don't waste time
        // producing an error report that will never be read
        final AtomicBoolean result = new AtomicBoolean(false);
        response.getCoyoteResponse().action(ActionCode.IS_IO_ALLOWED, result);
        if (!result.get()) 
            return;
        

        try 
            try 
                response.setContentType("text/html");
                response.setCharacterEncoding("utf-8");
             catch (final Throwable t) 
                ExceptionUtils.handleThrowable(t);
                if (container.getLogger().isDebugEnabled()) 
                    container.getLogger().debug("status.setContentType", t);
                
            
            final Writer writer = response.getReporter();
            if (writer != null) 
                // If writer is null, it's an indication that the response has
                // been hard committed already, which should never happen
                writer.write("<!doctype html><html lang=\"en\"><title>error</title><body>Error occured.</body></html>");
                response.finishResponse();
            
         catch (IOException | IllegalStateException e) 
            // Ignore
        
    

import org.apache.catalina.Container;
import org.apache.catalina.core.StandardHost;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyConfig 
    // https://docs.spring.io/spring-boot/docs/2.5.4/reference/htmlsingle/#howto-use-tomcat-legacycookieprocessor
    // https://github.com/spring-projects/spring-boot/issues/21257#issuecomment-745565376
    @Bean
    public WebServerFactoryCustomizer<TomcatServletWebServerFactory> errorReportValveCustomizer() 

        return (factory) -> 
            factory.addContextCustomizers(context -> 
                final Container parent = context.getParent();
                if (parent instanceof StandardHost) 
                    // above class FQCN
                    ((StandardHost) parent).setErrorReportValveClass(
                        "com.example.foo.bar.CustomErrorReportValve");
                
            );
        ;
    

【讨论】:

以上是关于如何在 Spring Boot 应用程序的错误页面上屏蔽 Apache 版本?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Spring Boot 应用程序中删除白标错误页面?

Spring Boot如何解决Whitelabel错误页面

如何在 Spring Boot 中创建自定义错误页面

当用户使用 Spring Boot 登录失败时,如何在登录页面中显示错误消息?

spring boot 错误页面配置

在 Spring Boot Web 应用程序中刷新后的 Whitelabel 错误页面