Spring-boot ErrorPage 不适用于独立 Tomcat

Spring-boot ErrorPage not working with standalone Tomcat

我仍在努力让 Spring-boot 错误页面的东西在部署了 WAR 文件的独立 tomcat 中完全工作。

我的配置class如下:

@Configuration
@ComponentScan
@EnableAutoConfiguration(exclude = [ GroovyTemplateAutoConfiguration, SecurityAutoConfiguration, ErrorMvcAutoConfiguration, JmxAutoConfiguration ] )
class Application extends SpringBootServletInitializer {

    @Override protected SpringApplicationBuilder configure( SpringApplicationBuilder application ) {
        application.sources( Application )
    }

还有我的错误处理配置如下:

@Configuration
class ErrorConfiguration implements EmbeddedServletContainerCustomizer {

    @Override public void customize( ConfigurableEmbeddedServletContainer container ) {
        container.addErrorPages(new ErrorPage( HttpStatus.NOT_FOUND, "/errors/404" ))
    }

此信息似乎已被使用,但并不像我预期的那样 - 如果我只是转到一个不存在的 URL 然后我会得到 tomcat 默认 404 页面 - 但是,Spring 似乎返回了我的 ErrorPage 路径,因为 Tomcat 页面如下所示:

HTTP Status 404 - //errors/404

type Status report

message //errors/404

description The requested resource is not available.

Apache Tomcat/7.0.54

如果我更改我的错误配置并使用不同的路径,那么该路径将作为 404 消息通过 - 有人知道我错过了什么吗?我希望消息类似于 "Not found" 和路径 /errors/404 用于解析 view/controller 以呈现错误页面。


更新 我在我的网络配置中将错误路径映射为标准视图控制器:

@Configuration
@EnableWebMvc
class WebMvcConfiguration extends WebMvcConfigurerAdapter {

    /**
     * Register static views that dont need controller calls - map URLs direct to views
     */
    @Override public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/errors/404").setViewName("errors/404")
        registry.addViewController("/errors/500").setViewName("errors/500")
    }

此外,如果我直接进入浏览器中的错误路径 - /errors/404 - 然后我会得到我期望的错误页面。


更新 2

我创建了一个带有自动错误处理功能的虚拟 Spring 引导 Web 应用程序,并将其部署到我在 Eclipse 中运行的 tomcat,并且白标签错误页面显示正确。然后我将它部署到我的开发服务器 tomcat 并且白标错误页面停止工作(我看到默认的 tomcat 404 页面)。

我的 web.xml 在两者上是相同的(将 web.xml 从 eclipse 复制到开发服务器)并且 server.xml 在下面(实际上与 eclipse 版本基本相同)

<Server port="8005" shutdown="SHUTDOWN">
  <Listener SSLEngine="on" className="org.apache.catalina.core.AprLifecycleListener"/>
  <Listener className="org.apache.catalina.core.JasperListener"/>
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/>
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>
  <GlobalNamingResources>
    <Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase"/>
  </GlobalNamingResources>

  <Service name="Custom">
    <Executor name="tomcatThreadPoolwr" minSpareThreads="4" maxThreads="500" namePrefix="catalina-execwr-"></Executor>
    <Connector port="8081" protocol="org.apache.coyote.http11.Http11Protocol" connectionTimeout="20000" redirectPort="8443" executor="tomcatThreadPoolwr" maxThreads="10"></Connector>
    <Connector port="9998" protocol="AJP/1.3" redirectPort="8445" maxThreads="500" tomcatAuthentication="false" connectionTimeout="21000"></Connector>
    <Engine jvmRoute="custom" name="Custom" defaultHost="localhost">
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"></Realm>
      </Realm>
      <Host name="localhost" autoDeploy="true" deployOnStartup="true"  unpackWARs="false" appBase="/tmp/dev/custom" workDir="/tmp/dev/custom/work" createDirs="true">
        <Context docBase="/tmp/dev/ROOT" path="/" reloadable="true" override="true"/>
        <Valve pattern="common" directory="/var/log/tmp" prefix="custom_access_log." className="org.apache.catalina.valves.AccessLogValve" suffix=".log" resolveHosts="false"/>
      </Host>
    </Engine>
  </Service>
</Server>

此外:

  1. 如果我直接导​​航到 /error,我会看到白标签页面,所以端点工作正常
  2. 如果我在 webroot 中创建一个名为 "error" 的文件,它会被拾取并显示。所以看起来应用程序正在尝试正确地重新路由我的 404,但由于某种原因只是在寻找 "error" 文件,而不是应用程序中的 "error" 端点

更新 3

我已经进一步调查,即使我在本地使用完全相同的 server.xml 和 web.xml,干净的 tomcat 安装它仍然可以在本地工作。

我还看到请求的 RequestDispatch 似乎有问题。

如果我在我的开发服务器上运行以下代码(任何地方,但例如从控制器)它不起作用:

request.getRequestDispatcher("/errors/404").forward(request,response);

但以下内容确实如此:

servletContext.getRequestDispatcher("/errors/404").forward(request,response);

(其中请求和响应是 HttpServletRequest/Response 并且 servletContext 是一个自动装配的 ServletContext 对象)

以上两个示例在干净的本地 tomcat 安装上都可以正常工作 - 有什么想法可能会导致请求链接 RequestDispatcher 出现问题,而 ServletContext RequestDispatcher 仍然有效吗? ErrorPageFilter 使用请求链接的 RequestDispatcher 所以遇到了这个问题。

最后是因为在 tomcat appBase 中创建了一个 ROOT 目录(这是作为 WAR 部署过程的一部分创建的)- 看起来像这样然后引起了一些与两个 ROOT 上下文的混淆(WAR 被部署为 ROOT war)。

正在修复 tomcat 设置,因此它只有 WAR 文件,这开始工作了。