当我更改部署描述符(例如library(readxl)
data = read_xls("NUTS 2010 - NUTS 2013.xls",sheet = "NUTS2010-NUTS2013")
table(data$X__5)
)或用新版本的Web应用程序替换apache-tomcat/conf/Catalina/localhost/myApp.xml
文件时,该文件将停止,然后使用来自{{1}的更新配置重新启动}或myApp.war
中的新应用程序版本。
在上下文路径myApp.xml
上收到的请求将获得一个myApp.war
状态错误页面,直到应用程序完全加载并启用服务请求为止。
我想对此进行自定义,并显示一个/myApp
错误页面。某处是否有配置指令?
到目前为止,我想到的解决方法包括:
404
并用自定义Servlet实现替换503 temporary unavailable
。apache-tomcat/conf/web.xml
中提供一个微型自定义Web应用程序,以根据需要进行响应。这些有点笨拙,恕我直言,我希望有人知道更轻巧的解决方案。我还知道可以部署同一上下文路径的多个版本(org.apache.catalina.servlets.DefaultServlet
,apache-tomcat/webapps/ROOT/
,...),但还不能并行运行多个应用程序实例。
答案 0 :(得分:1)
我最后写了一个小服务器程序,它以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>
并且必须通过context.xml
获得特权:
<Context privileged="true"/>
这是映射到<url-pattern>/</url-pattern>
的servlet:
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();
}
}