ApacheTomcat:如何在[重新]部署期间防止404状态

ApacheTomcat:如何在[重新]部署期间防止404状态,tomcat,servlets,Tomcat,Servlets,当我更改部署描述符(例如apache-tomcat/conf/Catalina/localhost/myApp.xml)或用新版本的web应用程序替换myApp.war文件时,将使用myApp.xml中的更新配置或myApp.war中的新应用程序版本停止并再次启动部署描述符 进入上下文路径/myApp的请求将获得404状态错误页面,直到应用程序完全加载并启用以服务请求 我想对此进行自定义,并提供一个503临时不可用错误页面。在什么地方有配置指令吗 到目前为止,我想到的解决办法包括: 编辑apa

当我更改部署描述符(例如
apache-tomcat/conf/Catalina/localhost/myApp.xml
)或用新版本的web应用程序替换
myApp.war
文件时,将使用
myApp.xml
中的更新配置或
myApp.war
中的新应用程序版本停止并再次启动部署描述符

进入上下文路径
/myApp
的请求将获得
404
状态错误页面,直到应用程序完全加载并启用以服务请求

我想对此进行自定义,并提供一个
503临时不可用
错误页面。在什么地方有配置指令吗

到目前为止,我想到的解决办法包括:

  • 编辑
    apachetomcat/conf/web.xml
    并用定制Servlet实现替换
    org.apache.catalina.servlets.DefaultServlet
    ,根据需要进行响应
  • 或者在apachetomcat/webapps/ROOT/中提供一个根据需要响应的小型定制web应用程序

这是一个有点黑客imho,我希望有人知道一个更轻量级的解决方案。我还知道可以部署同一上下文路径的多个版本(
myApp#v001.xml
myApp#v002.xml
,…)但是,让多个应用程序实例并行运行还不是一个选项。

我最后编写了一个小servlet,它被部署为
ROOT.war
,并检查是否存在不可用(=停止)的部署以及匹配的上下文路径。如果是,则返回503状态,否则返回404状态

为了访问国外部署,除了servlet api之外,应用程序还依赖于tomcat catalina:

<dependencies>
    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-servlet-api</artifactId>
        <version>${tomcatVersion}</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-catalina</artifactId>
        <version>${tomcatVersion}</version>
        <scope>provided</scope>
    </dependency>
</dependencies>
这是映射到
/
的servlet:


如果多个应用程序版本不是一个选项,我怀疑在前面安装负载平衡器的情况下运行两台服务器也不是一个选项。这就是我们所做的,也是大多数人所做的。@Kukeltje我们使用IIS->AJP->Tomcat进行部署。我能告诉isapiredirector有一个工人下岗一两分钟吗?哦,我。。。嗯,我们在ApacheTomcat前面的ApacheHTTP中有一个“负载平衡”模块。该模块请求一个附加的基本webapp纯html页面(部署在tomcat中),如果该页面不存在(根本没有响应或返回404)或返回“false”/0,则它将从集群中删除该服务器,并且只使用其他服务器。如果我们再次将其更改为包含true/1,它将再次开始使用此服务器。将询问我们的网络人员模块的名称。IIS可能也有类似的情况
<Context privileged="true"/>
package my.pkg;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.catalina.Container;
import org.apache.catalina.ContainerServlet;
import org.apache.catalina.Context;
import org.apache.catalina.Host;
import org.apache.catalina.Wrapper;

public class DefaultErrorPageServlet extends HttpServlet implements ContainerServlet {

    private static final long serialVersionUID = 1L;
    private Host host;
    private Wrapper wrapper;

    @Override
    protected void doGet(final HttpServletRequest req, final HttpServletResponse resp)
            throws ServletException, IOException {
        if (matchesForeignUnavailableContextPath(req)) {
            // 503 if there is an unavailabe deployment matching the request
            sendUnavailable(resp);
        } else {
            // 404 if there is no unavailabe deployment matching the request
            sendNotFound(resp);
        }
    }

    @Override
    protected void doPost(final HttpServletRequest req, final HttpServletResponse resp)
            throws ServletException, IOException {
        // Redirect to make the client GET the requested URL
        resp.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
        final String requestUrl = req.getRequestURL().toString();
        resp.addHeader("Location", requestUrl);
    }

    private boolean matchesForeignUnavailableContextPath(HttpServletRequest req) {
        if (null != host) {
            Container[] children = host.findChildren();
            for (Container container : children) {
                String contextName = container.getName();
                Context context = (Context) host.findChild(contextName);
                if (null != context && !contextName.isEmpty()) {
                    String contextPath = context.getPath();
                    boolean started = context.getState().isAvailable();
                    String requestUri = req.getRequestURI();
                    if (!started && requestUri.startsWith(contextPath)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    private void sendNotFound(HttpServletResponse resp) throws IOException {
        resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
        resp.getWriter().append(
            // HTML document to show on 404 not found
        );
    }

    private void sendUnavailable(HttpServletResponse resp) throws IOException {
        resp.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
        resp.getWriter().append(
        // HTML document to show on 503 unavailable
        );
    }

    @Override
    public Wrapper getWrapper() {
        return wrapper;
    }

    @Override
    public void setWrapper(Wrapper wrapper) {
        // see also org.apache.catalina.manager.ManagerServlet.setWrapper(Wrapper)
        if (null == wrapper) {
            return;
        }
        this.wrapper = wrapper;
        final Context context = (Context) wrapper.getParent();
        this.host = (Host) context.getParent();
    }
}