try-with-resource vs java.lang.IllegalStateException:提交响应后无法调用 sendError()

try-with-resource vs java.lang.IllegalStateException: Cannot call sendError() after the response has been committed

我的 RSS servlet 将 try-with-resource 用于 HttpServletResponseOutputStream out 及其编写器。在某些情况下,生成 RSS 文档时会抛出 SomeException,在这种情况下,我需要 return 向客户端发送 HTTP 状态 500:

try (ServletOutputStream out = response.getOutputStream();
     OutputStreamWriter writer = new OutputStreamWriter(out, "utf-8")) {
        response.setContentType("text/xml");

        // Generate RSS here

    } catch (SomeException e) {
        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
        return;
    }

然而,在调用 response.sendError() 时,$out$ 已经关闭,我说 IllegalStateException 说响应已经提交(关闭流似乎提交自动响应)。

如果我将 outwriter 的初始化移动到 try 块之外,并在 finally 块中关闭它们(pre-Java7 方式),错误代码已正确发送。

我想知道是否有一种方法可以继续使用 try-with-resource 并在出现异常时仍然能够 return 错误代码。

谢谢!

您不需要关闭不是您自己创建的资源。容器自行创建底层 OutputStream,因此也自行负责正确关闭它。您应该想象容器已经在 servlet 的 doXxx() 方法周围放置了一个 try-with-resources。另见 Should I close the servlet outputstream?

换句话说,doXxx()OutputStream 上的整个 try-with-resources 是不必要的。

就这样:

try {
    // Generate RSS here

    OutputStreamWriter writer = new OutputStreamWriter(response.getOutputStream(), "UTF-8")) {
    response.setContentType("text/xml");

    // Write RSS here.

} catch (SomeException e) {
    response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
}

与具体问题无关,如果您将任何已检查的异常重新抛出为 ServletException,那么容器也将自行处理正确的响应代码和留言。

try {
    // ...
} catch (SomeException e) {
    throw new ServletException(e);
}