我正在使用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();
}
}
}
这种实现有两个问题:
- 它在Eclipse中生成一个弃用警告,因为HttpServlet响应.setStatus(sc,msg)已弃用
- 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)
,这将刷新缓冲区。