代码之家  ›  专栏  ›  技术社区  ›  Selaron Egesa Michael

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

  •  2
  • Selaron Egesa Michael  · 技术社区  · 6 年前

    当我更改部署描述符时(例如。 apache-tomcat/conf/Catalina/localhost/myApp.xml )或者更换 myApp.war 如果我的web应用程序有了新版本,它将停止运行,并使用中更新的配置重新启动 myApp.xml 或者新的应用程序版本 我的应用。战争 .

    在上下文路径中传入的请求 /myApp 会得到一个 404 状态错误页面,直到应用程序完全加载并启用服务请求。

    我想定制这个,并呈现一个 503 temporary unavailable 改为错误页面。在什么地方有配置指令吗?

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

    • 编辑 apache-tomcat/conf/web.xml 替换 org.apache.catalina.servlets.DefaultServlet 通过自定义Servlet实现,根据需要进行响应。
    • 或者在中提供一个小型定制web应用程序 apache-tomcat/webapps/ROOT/ 按要求回应。

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

    0 回复  |  直到 5 年前
        1
  •  1
  •   Selaron Egesa Michael    5 年前

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

    为了访问该应用程序所依赖的国外部署 tomcat-catalina 除了servlet api:

    <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>
    

    而且必须通过 context.xml :

    <Context privileged="true"/>
    

    这是映射到的servlet <url-pattern>/</url-pattern> :

    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();
        }
    }