应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()吗?

我找不到一个权威的答案,用谷歌search。 在Java servlet中,可以通过response.getOutputStream()或response.getWriter()来访问响应主体。 这个stream被写入后,是否应该调用.close()?

一方面,布洛赫的劝告总是closures输出stream。 另一方面,我不认为在这种情况下,有一个潜在的资源需要closures。 套接字的打开/closures在HTTP级别进行pipe理,以允许持久连接等。

通常你不应该closuresstream。 servlet容器将在servlet完成运行后自动closuresstream,作为servlet请求生命周期的一部分。

例如,如果你closures了stream,如果你实现了一个filter ,它将不可用。

说了这么多,如果你closures它,只要你不再尝试使用它,没有什么不好的事情会发生。

编辑: 另一个filter的链接

EDIT2:adrian.tarau是正确的,如果你想在servlet完成它的事情之后改变响应,你应该创build一个扩展HttpServletResponseWrapper的包装并缓冲输出。 这是为了防止输出直接到客户端,但也允许你保护,如果这个servletclosuresstream,按照这个摘录(重点我):

修改响应的筛选器通常必须在将响应返回给客户端之前捕获该响应。 这样做的方法是将生成响应的servlet传递给一个站点stream。 该标准stream阻止servlet在完成时closures原始响应stream,并允许filter修改该servlet的响应。

文章

从Sun的官方文章中可以推断,从servletclosures输出stream是正常现象,但不是强制性的。

他们的一般规则是这样的:如果你打开了stream,那么你应该closures它。 如果你没有,你不应该。 确保代码是对称的。

HttpServletResponse的情况下,它不太清楚,因为调用getOutputStream()是一个打开stream的操作并不明显。 Javadoc只是说它“ Returns a ServletOutputStream ”; 类似于getWriter() 。 无论哪种方式,清楚的是HttpServletResponse “拥有”stream/作家,它(或容器)负责再次closures它。

所以要回答你的问题 – 不,你不应该在这种情况下closuresstream。 容器必须这样做,如果你之前进入容器,你可能会冒险在你的应用程序中引入微妙的错误。

如果有可能在“包含”资源上调用filter,则绝对不能closures该stream。 这将导致包含资源失败,出现“streamclosures”exception。

您应该closuresstream,因为调用getOutputStream(),代码更清洁,并且stream不会作为parameter passing给您,通常您只是使用它而不尝试closures它。 Servlet API没有规定如果输出stream可以被closures或者不能被closures,在这种情况下你可以安全地closuresstream,如果servlet没有closuresstream,任何容器都会closuresstream。

这里是Jetty中的close()方法,如果它没有closures,它们会closuresstream。

 public void close() throws IOException { if (_closed) return; if (!isIncluding() && !_generator.isCommitted()) commitResponse(HttpGenerator.LAST); else flushResponse(); super.close(); } 

另外作为一个Filter的开发者,你不应该假定OutputStream没有closures,如果你想在servlet完成它的工作之后改变内容,你应该总是传递另一个OutputStream。

编辑:我总是closuresstream,我没有任何问题与Tomcat /docker。 我不认为你应该有任何新旧容器的问题。

另一个反对closuresOutputStream论据。 看看这个servlet。 它引发一个exception。 该exception在web.xml中映射到错误JSP:

 package ser; import java.io.*; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.*; @WebServlet(name = "Erroneous", urlPatterns = {"/Erroneous"}) public class Erroneous extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=UTF-8"); PrintWriter out = resp.getWriter(); try { throw new IOException("An error"); } finally { // out.close(); } } } 

web.xml文件包含:

 <?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <session-config> <session-timeout> 30 </session-timeout> </session-config> <error-page> <exception-type>java.io.IOException</exception-type> <location>/error.jsp</location> </error-page> </web-app> 

和error.jsp:

 <%@page contentType="text/html" pageEncoding="UTF-8" isErrorPage="true"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Error Page</title> </head> <body> <h1><%= exception.getMessage()%></h1> </body> </html> 

当您在浏览器中加载/Erroneous时,您会看到显示“错误”的错误页面。 但是,如果您取消注释上述servlet中的out.close()行,重新部署de application,并重新加载/Erroneous您将在浏览器中看不到任何内容。 我不知道实际发生了什么,但我想out.close()可以防止error handling。

使用Netbeans 7.4testingTomcat 7.0.50,Java EE 6。