Java Servlet API - How can I set the response status and reason phrase without commiting the response

StackOverflow https://stackoverflow.com/questions/20140376

Pregunta

I am writing a REST application using Tomcat and Spring WebMVC.

I want to signal errors to my client using HTTP status codes along with some XML payload that contains more information about what went wrong.

To catch all errors regardless of where they occur, I have written a Filter which wraps the response and overrides the sendError() method:

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();
    }
  }
}

This implementation has two problems:

  1. It generates a deprecation warning in Eclipse, since HttpServletResponse.setStatus(sc, msg) is deprecated.
  2. The HTTP response header generated by Tomcat is not correct, it starts with the first line "HTTP/1.1 500 OK". 500 is correct, but instead of OK the reason phrase should be "Internal Server Error".

How can I implement my filter so that it does the right thing and is free of deprecation warnings? Both alternatives named in the Javadoc are not usable for me:

  • sendError(sc, msg) is not usable, since it commits the response body and I can't write XML payload any more
  • setStatus(sc) with just the error code is theoretically usable, but it also creates the hardcoded "OK" string in the first line of the response header.
¿Fue útil?

Solución

There is unfortunately no way to avoid the deprecation warning. As you already mention yourself, the two alternatives which are referred to in the API documentation do not cover the same functionality. You may of course annotate your method with @SuppressWarnings("deprecation") to indicate that the usage of the deprecated method is intended.

The other thing, that Tomcat does not use your message string, even if one is provided, is a configuration issue. For some strange reason, Tomcat will by default ignore the provided message string and use a default error message based on the passed return code. You must set the system property org.apache.coyote.USE_CUSTOM_STATUS_MSG_IN_HEADER to true to force Tomcat to use your provided error message instead. More details on this can be found in the Tomcat documentation.

Otros consejos

As an alternative answer - you could first write the XML payload, without calling flush/flushBuffer, and only after that do sendError(int, String), which would flush the buffer.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top