在 Tomcat 禁用所有默认的 HTTP 错误响应内容

默认情况下,如果 Tomcat 遇到类似 HTTP404的情况,它会将一些 HTML 内容发送回客户机。我知道通过 web.xml一个 <error-page> 可以配置定制这个内容。

然而,我只是希望 Tomcat 在响应内容方面采用 什么都不发(当然,我仍然希望使用状态代码)。有什么简单的配置方法吗?

我试图避免 A)显式地从 Servlet 在响应流上发送空内容,B)在 web.xml中为一大堆 HTTP 错误状态配置自定义错误页面。

对于一些背景知识,我正在开发一个 HTTPAPI 并控制我自己的响应内容。例如,对于 HTTP500,我将在包含错误信息的响应中填充一些 XML 内容。对于像 HTTP404这样的情况,HTTP 响应状态对于客户端来说已经足够了,tomcat 发送的内容是不必要的。如果有别的方法,我愿意听。

编辑: 经过持续的调查,我仍然找不到太多的解决办法。如果有人可以明确地说这是不可能的,或者提供一个资源,证明它不会工作,我会接受这个作为一个答案,并试图解决它。

70851 次浏览

为什么不用一个空的 HTML 页面来配置 <error-page>元素呢?

如果您不希望 tomcat 显示错误页面,那么不要使用 sendError (...) ,而是使用 setStatus (...)。

例如,如果你想给出一个405响应,那么你就给

response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
response.getWriter().println("The method " + request.getMethod() +
" is not supported by this service.");

还要记住不要从 servlet 中抛出任何异常。相反,捕获 Exception 并再次自己设置 statusCode。

也就是说。

protected void service(HttpServletRequest request,
HttpServletResponse response) throws IOException {
try {


// servlet code here, e.g. super.service(request, response);


} catch (Exception e) {
// log the error with a timestamp, show the timestamp to the user
long now = System.currentTimeMillis();
log("Exception " + now, e);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.getWriter().println("Guru meditation: " + now);
}
}

当然,如果你不想要任何内容,那么就不要写任何东西给作者,只要设置状态。

正如 Heikki 所说,设置状态而不是 sendError()会导致 Tomcat 不接触响应实体/body/payload。

如果您只想发送没有任何实体的响应头,比如在我的示例中,

response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentLength(0);

使用 Content-Length: 0,即使使用 print()也不会产生任何效果,例如:

response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentLength(0);
response.getWriter().print("this string will be ignored due to the above line");

客户会收到这样的东西:

HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 0
Date: Wed, 28 Sep 2011 08:59:49 GMT

如果您想发送一些错误消息,请使用具有消息长度(零以外)的 setContentLength(),或者您可以将其留给服务器

阻止 Tomcat 发送任何错误主体的快速、稍微有点脏但是简单的方法是针对 Tomcat 主机调用 setErrorReportValveClass,并使用一个自定义的错误报告阀,该报告阀重写 report,不执行任何操作。即:

public class SecureErrorReportValve extends ErrorReportValve {


@Override
protected void report(Request request,Response response,Throwable throwable) {
}


}

并设置为:

  ((StandardHost) tomcat.getHost()).setErrorReportValveClass(yourErrorValveClassName);

如果你想发送你的信息,并且认为 Tomcat 不应该破坏它,那么你需要这样的东西:

@Override
protected void report(final Request request, final Response response, final Throwable throwable) {
String message = response.getMessage();
if (message != null) {
try {
response.getWriter().print(message);
response.finishResponse();
} catch (IOException e) {
}
}
}

虽然这个问题有点老,但我也碰到了这个问题。首先,雄猫的行为是绝对正确的。这是根据 Servlet 规范。人们不应该违反规范改变 Tomcat 的行为。正如 Heikki Vesalainen 和 mrCoder 提到的,只使用 setStatussetStatus

我已经用 Tomcat 提出了一个 罚单来改进 sendError的文档。

尽管它符合 Servlet 规范,但出于安全原因,我不希望 tomcat 或任何其他 Servlet 容器发送错误详细信息。我也有点挣扎。经过探索和尝试,解决方案可以归结为:

  1. 正如其他人提到的,不要使用 sendError(),而是使用 setStatus()(在 Jersey 框架中你可以选择)
  2. 像 Spring Security 这样的框架使用 sendError()..。
  3. 写一个 Filter
    将对 sendError()的调用重定向到 setStatus()
    在最后刷新响应,以防止容器进一步修改响应

这里可以找到这样做的一个小示例 servlet 过滤器

虽然这并不能准确地回应关于这个问题的“不发送任何东西”声明,在 Clive Evans 的回答的 wave 中,我发现在 tomcat 中,你可以让那些过于冗长的文本远离错误页面,而不需要创建一个自定义的 ErrorReportValve。

您可以通过“ server.xml”上的两个参数“ showReport”和“ showServerInfo”来完成这个定制 ErrorReportValve:

<Valve className="org.apache.catalina.valves.ErrorReportValve" showReport="false" showServerInfo="false" />

链接到官方文件。

在 tomcat 7.0.55上对我有用,在 tomcat 7.0.47上没有用(我想是因为在下面的链接 http://www.mail-archive.com/users@tomcat.apache.org/msg113856.html上报道了一些东西)

web.xml中配置 <error-page>元素

编辑 $CATALINA_HOME/conf/web.xml,在结尾添加以下 <error-page>,保存并重新启动 tomcat

<web-app>


...
...
...


<error-page>
<error-code>404</error-code>
<location>/404.html</location>
</error-page>


<error-page>
<error-code>500</error-code>
<location>/500.html</location>
</error-page>


<error-page>
<error-code>400</error-code>
<location>/400.html</location>
</error-page>


</web-app>
  • 尽管我没有为那些指定的 location值(例如 /400.html)创建有效的路由,但是它的工作效果和我预期的一样好

之前

enter image description here

之后

enter image description here