【问题标题】:Setting both error message and body from servlet从 servlet 设置错误消息和正文
【发布时间】:2011-04-22 14:13:25
【问题描述】:

我想写一个 servlet,它会像这样返回一个 http 响应:

HTTP/1.1 500 <short custom message>
Content-Length: ...

<longer custom message>

原因是我希望程序化客户端能够处理响应消息以获取特定响应,但我也想在响应正文中填写更长的解释,以便使用浏览器轻松点击。

现在,HttpServletResponse 有一个 sendError(int, String) 方法,它允许我指定错误代码和消息。 javadocs只说消息将嵌入某种html页面,但没有设置http响应消息。调用此方法后,您将无法在响应中写入任何其他内容。在我的测试(使用码头)中,该消息同时用于 http 响应和 html 正文,这对我来说很好,除了我想指定两个不同的字符串并且我不认为 http 响应的设置消息通过不同的实现得到保证。

还有一个 setStatus(int) 方法,您可以使用任何代码调用它,然后您可以编写自己的 html 正文。这很接近,除了你不能指定http响应消息。

最后,有一个 setStatus(int, String) 方法实际上完全符合我的要求,但由于某种歧义,它已被弃用。我假设一些 servlet 容器正在将消息写入响应正文并关闭响应。

除了使用不推荐使用的方法之外,我假设我在这里搞砸了,但我很好奇是否有人知道任何技巧?

【问题讨论】:

    标签: java servlets httpresponse


    【解决方案1】:

    似乎所有用于在 HTTP 中设置原因短语的 API 都因此而过时:

    RFC 7230,超文本传输​​协议 (HTTP/1.1):消息语法和路由,2014 年 6 月。Section 3.1.2

    reason-phrase 元素存在的唯一目的是提供 与数字状态代码相关的文本描述, 主要是出于对早期互联网应用协议的尊重 更频繁地与交互式文本客户端一起使用。 一个 客户应该忽略原因短语内容

    Tomcat 在version 8.5.0 中删除了对org.apache.coyote.USE_CUSTOM_STATUS_MSG_IN_HEADER 属性的支持。

    【讨论】:

    • 谢谢。在这一点上,我不再记得为什么我希望客户能够检查原因短语,但这似乎不是一个好主意。
    【解决方案2】:

    使用 JBoss 6 我得出的结论是,必须在调用 getWriter 以禁用 Jboss 自定义错误页面响应后设置响应代码。我猜这个实现会根据响应的状态提供不同的编写器。

    response.getWriter().print(message);
    response.setStatus(500);
    

    【讨论】:

      【解决方案3】:

      好吧,抱歉,为错误响应提供正文的最明显原因是在发生错误时在浏览器中显示人类可读的内容。这就是为什么生成 HTML 是 Servlet 规范中 sendError 的默认行为的原因。

      就我而言,我想要一些不同的东西,因为我正在创建 Web 服务,如果一切正常,这个具体的服务不会返回响应。

      【讨论】:

        【解决方案4】:

        如果您想在标题中添加自定义错误消息,为什么不使用response.addHeader(String, String) 添加您自己的标题?将此与马特 b 的答案结合起来可以完成这项工作。

        【讨论】:

          【解决方案5】:

          还有一个 setStatus(int) 方法,您可以使用任何代码调用它,然后您可以编写自己的 html 正文。这很接近,只是您不能指定 http 响应消息。

          您有什么理由不使用response.setStatus(500) 设置HTTP 状态码,然后写入响应的输出流?

          这就是在最低级别实现“写入响应正文”的方式。

          这是一个例子:

          public class ErrorServlet extends HttpServlet {
          
              @Override
              protected void service(HttpServletRequest req, HttpServletResponse resp)
                  throws ServletException, IOException {
          
                  // 500 error
                  resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                  resp.getWriter().print("<html><head><title>Oops an error happened!</title></head>");
                  resp.getWriter().print("<body>Something bad happened uh-oh!</body>");
                  resp.getWriter().println("</html>");
              }
          }
          

          web.xml:

          <web-app>
              <servlet>
                  <servlet-name>myerror</servlet-name>
                  <servlet-class>brown.testservlet.ErrorServlet</servlet-class>
              </servlet>
              <servlet-mapping>
                  <servlet-name>myerror</servlet-name>
                  <url-pattern>/myErrorPage</url-pattern>
              </servlet-mapping>
          </web-app>
          

          还有输出:

          $ curl -I http://localhost:8080/testservlet/myErrorPage  
          HTTP/1.1 500 Internal Server Error  
          Content-Length: 108  
          Server: Jetty(6.1.16)  
          
          $ curl -v http://localhost:8080/testservlet/myErrorPage
          * About to connect() to localhost port 8080 (#0)
          *   Trying 127.0.0.1... connected
          * Connected to localhost (127.0.0.1) port 8080 (#0)
          > GET /testservlet/myErrorPage HTTP/1.1
          > User-Agent: curl/7.20.0 (i686-pc-mingw32) libcurl/7.20.0 OpenSSL/0.9.8k zlib/1.2.3
          > Host: localhost:8080
          > Accept: */*
          >
          < HTTP/1.1 500 Internal Server Error
          < Content-Length: 108
          < Server: Jetty(6.1.16)
          <
          <html><head><title>Oops an error happened!</title></head><body>Something bad happened uh-oh!</body></html>
          * Connection #0 to host localhost left intact
          * Closing connection #0
          

          【讨论】:

          • 是的,你引用的我的问题部分表明我理解这个选项。它还指出,这不允许您设置 http 响应消息(示例中的“内部服务器错误”,由 servlet 容器自动提供)。
          • 即使response.setStatus(int, String) 已被弃用,您应该可以使用它来设置状态行消息
          【解决方案6】:

          您可以通过在 web.xml 中指定错误特定页面来自定义错误页面:

          <error-page>
            <error-code>500</error-code>
            <location>/error500.jsp</location>
          </error-page>
          

          在 jsp 文件中,您可以使用请求属性来显示自定义消息和其他信息。

          【讨论】:

          • 谢谢,这是一个很好的观点,可能会帮助大多数人解决这个问题 :) 我碰巧在没有设置整个 Web 应用程序的情况下使用嵌入式码头:这是一个完全独立的 servlet。我至少可以四处看看是否可以在代码中设置错误页面,但我可能会决定让程序调用者在正文中查看详细信息。
          • 只是想提一个我遇到的警告。如果你尝试使用 html 页面而不是 jsp,虽然会显示错误页面内容,但服务器不会发送正确的状态码。
          猜你喜欢
          • 2015-06-07
          • 2011-11-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多