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


68

默认情况下,Tomcat的发送一些HTML内容返回给客户端,如果它通过遇到类似的HTTP 404。我知道,web.xml一个<error-page> 可以配置自定义此内容。

但是,我只希望Tomcat不发送任何响应内容(当然,我仍然希望状态码)。有什么方法可以轻松配置它吗?

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

在某些背景下,我正在开发HTTP API并控制自己的响应内容。例如,对于HTTP 500,我在响应中填充了一些XML内容,其中包含错误信息。对于HTTP 404之类的情况,HTTP响应状态对于客户端来说足够了,并且tomcat正在发送的内容是不必要的。如果有其他方法,我愿意听。

编辑: 经过不断调查,我仍然找不到解决方案的方法。如果有人可以肯定地说这是不可能的,或者提供了一个资源证明它行不通,那么我将接受它作为答案并尝试解决它。


7
我没有超载代码的含义,而是按预期使用它们。这是针对REST API的-例如,如果有人在我的API中的某个资源上执行GET,但没有找到它,则将响应状态设置为404。如果我遇到某种奇怪的错误,我将状态设置为500,并在响应中提供了一些错误内容。但是我想要对该内容进行排他控制-我不希望Tomcat返回HTML或其他内容。如果要返回内容,我希望我的Servlet成为这样做的对象。
罗布·赫鲁斯卡

4
我刚刚还发现,Servlet的3似乎允许一个渔获物,所有<错误页>:static.springsource.org/spring/docs/3.2.0.BUILD-SNAPSHOT/...
埃里希Eichinger

@ErichEichinger-这是有用的信息,感谢您的传递。
罗布·赫鲁斯卡

Answers:


45

如果您不想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);
  }
}

当然,如果您不想要任何内容​​,则只需不向写者写任何东西,只需设置状态即可。


使用print()代替println()会导致其他换行符。如果您要发送空字符串,这特别有用Content-Length: 0
-manikanta

3
我认为这样做的真正原因是因为您已写入输出流。我相信,如果你简单地设置状态和不写什么反应,Tomcat将发送默认的错误响应为405
亚光b

1
仅仅设置状态代码似乎不足以抑制标准错误页面(至少,不是基于我的经验)。
格雷格·布朗

1
我不得不要求flush()编写者确保我的内容不会被Tomcat覆盖。
micpalmia

1
抛出异常时,捕获异常似乎不起作用ClassNotFoundException。错误仍然显示
user2914191 '18

39

尽管这并不能完全回答问题和Clive Evans的回答,但我发现在tomcat中,您可以使那些冗长的文本从错误页面移开而无需创建自定义ErrorReportValve。

您可以通过“ server.xml”上的2个参数“ 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


6
使用Tomcat 8.出色的解决方案!
eis 2015年

3
Tomcat文档说,<Valve />元素可以放在server.xml中的<Engine />,<Host />或<Context />元素内。对我来说,将阀放置在<Engine />元素内是行不通的,但将其放置在单个<Host />元素内却行得通。文档还说,Tomcat将所有不匹配的主机名路由到<Engine />元素的defaultHost属性中设置的<Host />元素。为确保未显示指向主机/上下文外部位置的URL,错误消息已编译到Tomcat中,因此需要确保将此<Valve />添加为默认的<Host />。
猫头鹰

12

阻止Tomcat发送任何错误正文的一种快速,稍微肮脏但简单的方法是针对tomcat主机调用setErrorReportValveClass,它具有一个自定义的错误报告阀,该阀会覆盖报告而不执行任何操作。即:

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) {
        }
    }
}

这很棒!我喜欢在一个地方来控制它,而不必包装每个响应。更面向方面。
mckamey 2012年

确实是更好的解决方案!谢谢
Poni 2012年

2
随意指向规范的一部分,即您不应该使用Tomcat ErrorReportValve,它会将您的消息重写为包含您可能不想与外界共享的全部信息的消息,而是编写只是您的留言。我很感兴趣……
Clive Evans

1
另外,您可以编写自己的ErrorValve并在server.xml的<Host>元素中对其进行配置:<主机名=“ localhost” appBase =“ webapps” unpackWARs =“ true” autoDeploy =“ true” errorReportValveClass =“ security。 MyErrorValveImpl“>请参阅tomcat.apache.org/tomcat-7.0-doc/config/host.html
Erich Eichinger

1
如果您不使用Tomcat,那么您就不会因为Tomcat泄漏信息而受苦...
Clive Evans

9

如Heikki所说,设置状态而不是sendError()导致Tomcat不接触响应实体/主体/有效负载。

如果您只想发送没有任何实体的响应标头,例如我的情况,

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

绝招。使用Content-Length: 0print()即使使用,也将无效,例如:

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()带消息长度(不为零),或者可以将其留给服务器


9

尽管它符合Servlet规范,但出于安全原因,我不希望tomcat或任何其他Servlet容器发送错误详细信息。我也为此感到挣扎。搜索并尝试后,解决方案可以总结为:

  1. 正如其他人提到的,不要使用sendError()setStatus()而应 使用
  2. 像Spring Security这样的框架sendError()虽然使用...
  3. 写了Filter
    一个。将呼叫重定向sendError()setStatus()
    b。最后刷新响应,以防止容器进一步修改响应

可以在此处找到一个小示例servlet过滤器示例


4
+1指出框架具有预定义的行为并提供示例过滤器,正如我使用的Jersey一样,它使我发现了特定的Jersey属性
水汪汪的2016年

1
截止到2019年,@ watery发布的上述链接已死,现在正确的链接是jersey.github.io/apidocs/latest/jersey/org/glassfish/jersey/…–
maxxyme

2

尽管这个问题有点老了,但我也遇到了这个问题。首先,Tomcat的行为是绝对正确的。这是根据Servlet规范。不应违反规范更改Tomcat的行为。如Heikki Vesalainen和mrCoder所述,仅使用setStatussetStatus

要敬启者,我都提出了使用Tomcat改善的文档sendError


1
您能否阐明“绝对正确”的行为是什么意思?具体是哪种行为?Servlet规范的链接或摘录可能会有所帮助。我在3.0规范中找不到任何能够满足响应实际内容要求的内容,尤其是对于错误响应。就RFC2616而言,对实体内容的任何错误状态都没有任何要求。
罗布·赫鲁斯卡

当然是。这不限于RFC,而是Servlet规范本身。查阅Servlet规范3.0,第10.9.2和10.9.3章,Oracle的Servlet API JavaDocs中的sendError方法和对Tomcat Users Mailinglist的问题
Michael-O

1

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


2
我在问题中提到,我想避免为一堆状态配置错误页面(即使它们为空)。如果这是我唯一的选择,那么我想我必须-但我正在寻找替代方案。
罗布·赫鲁斯卡

1

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

编辑$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)创建有效的路由,它也可以按我期望的那样很好地工作

之前

在此处输入图片说明

在此处输入图片说明


您错过了OP表示他试图避免在[his] web.xml中为一堆HTTP错误状态配置[..]自定义错误页面的要点。
maxxyme

同意。然而,这对于那些以谷歌为例的人很有帮助。这个问题有很好的SEO评级。
约瑟夫·哈鲁什
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.