Java Servlet API-如何在不提交响应的情况下设置响应状态和原因短语



我正在使用Tomcat和SpringWebMVC编写一个REST应用程序。

我想使用HTTP状态代码和一些XML有效负载向我的客户端发出错误信号,这些有效负载包含更多关于错误的信息。

为了捕获所有错误,无论它们发生在哪里,我编写了一个Filter,它封装响应并覆盖sendError()方法:

private static final class GenericErrorResponseWrapper 
extends HttpServletResponseWrapper   
{
  @Override
  public void sendError(int sc, String msg) throws IOException {
    final HttpServletResponse wrappedResponse = (HttpServletResponse) getResponse();
    wrappedResponse.setStatus(sc, msg);
    wrappedResponse.setContentType("application/xml");
    PrintWriter writer = wrappedResponse.getWriter();
    try {
      SimpleXmlWriter xmlWriter = SimpleXmlWriterWrapper.newInstance(writer);
      xmlWriter.writeStartElement("ns2", "genericError")
      .writeAttribute("xmlns:ns2", "http://mynamespace")
      .writeCharacters(msg)
      .writeEndDocument().flush();
      writer.flush();
      wrappedResponse.flushBuffer();
    } finally {
      writer.close();
    }
  }
}

这种实现有两个问题:

  1. 它在Eclipse中生成一个弃用警告,因为HttpServlet响应.setStatus(sc,msg)已弃用
  2. Tomcat生成的HTTP响应标头不正确,它以第一行"HTTP/1.1 500 OK"开头。500是正确的,但原因短语应该是"内部服务器错误"而不是"确定"

我如何实现我的过滤器,使其做正确的事情,并且没有贬低警告?Javadoc中命名的两个备选方案对我来说都不可用:

  • sendError(sc,msg)不可用,因为它提交了响应主体,我不能再写XML负载了
  • 理论上,只有错误代码的setStatus(sc)是可用的,但它也会在响应头的第一行创建硬编码的"OK"字符串

不幸的是,没有办法避免弃用警告。正如您已经提到的那样,API文档中提到的两种替代方案并不包含相同的功能。当然,您可以使用@SuppressWarnings("deprecation")对方法进行注释,以表明不推荐使用的方法是有意的。

另一件事是,Tomcat不使用您的消息字符串,即使提供了消息字符串,也是配置问题。出于某种奇怪的原因,Tomcat默认情况下会忽略提供的消息字符串,并根据传递的返回代码使用默认的错误消息。您必须将系统属性org.apache.coyote.USE_CUSTOM_STATUS_MSG_IN_HEADER设置为true,才能强制Tomcat使用您提供的错误消息。有关这方面的更多详细信息,请参阅Tomcat文档。

作为一种替代方案,您可以先编写XML负载,而不调用flush/flushBuffer,然后再执行sendError(int, String),这将刷新缓冲区。

最新更新