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

问题描述 投票:93回答:5

在Java Servlet中,可以通过response.getOutputStream()response.getWriter()访问响应主体。 .close()写入后是否应该在此OutputStream上调用它?

一方面,Blochian要求始终关闭OutputStream。另一方面,我不认为在这种情况下有需要关闭的基础资源。套接字的打开/关闭在HTTP级别进行管理,以允许诸如持久连接之类的事情。

java servlets outputstream
5个回答
89
投票

通常,您不应该关闭流。在Servlet完成作为Servlet请求生命周期的一部分运行之后,Servlet容器将自动关闭流。

例如,如果您关闭流,则在实现Filter时将不可用。

说了这么多,只要您关闭它,只要您不尝试再次使用它,都不会发生任何不好的事情。

编辑:another filter link

EDIT2:adrian.tarau是正确的,因为如果您想在Servlet完成其操作后更改响应,则应创建一个扩展HttpServletResponseWrapper的包装器并缓冲输出。这是为了防止输出直接进入客户端,但也允许您保护servlet是否关闭流,如以下摘录(强调我的意思):

必须修改响应的过滤器通常捕获响应返回给客户端。通往的路这样做是为了传递servlet,生成响应流。替代流防止servlet从关闭原始响应流完成时,允许过滤器修改servlet的响应。

Article

[从Sun的官方文章可以推断出,关闭servlet的输出流是正常现象,但不是强制性的。


72
投票

它们的一般规则是:如果打开流,则应将其关闭。如果没有,就不应该。确保代码是对称的。

HttpServletResponse的情况比较不明确,因为调用getOutputStream()是否是打开流的操作并不明显。 Javadoc只是说它是“ Returns a ServletOutputStream”;对于getWriter()同样。无论哪种方式,都清楚的是HttpServletResponse“拥有”流/写入器,并且它(或容器)负责再次关闭它。

所以回答您的问题-不,在这种情况下,您不应该关闭信息流。容器必须做到这一点,如果您在此之前进入那里,则可能会在应用程序中引入细微的错误。


5
投票

如果有可能在“ included”资源上调用过滤器,则绝对应该not关闭流。这将导致包含资源失败,并出现“流关闭”异常。


4
投票

您应该关闭流,因为调用getOutputStream()会使代码更简洁,并且通常不使用流就将其作为参数传递给您,而通常只使用它而不尝试关闭它。 Servlet API并未声明如果可以关闭输出流或必须将其关闭,在这种情况下,您可以安全地关闭该流,如果该流没有被Servlet关闭,则其中的任何容器都将负责关闭该流。

这里是Jetty中的close()方法,如果未关闭流,它们将关闭流。

public void close() throws IOException
    {
        if (_closed)
            return;

        if (!isIncluding() && !_generator.isCommitted())
            commitResponse(HttpGenerator.LAST);
        else
            flushResponse();

        super.close();
    }

[作为Filter的开发者,您也不应该假定未关闭OutputStream,如果要在servlet完成其工作后更改内容,则应该始终传递另一个OutputStream。

编辑:我总是关闭流,并且Tomcat / Jetty没有任何问题。我认为无论新旧容器,您都不会遇到任何问题。


3
投票

[另一个反对关闭OutputStream的论点。看一下这个servlet。它引发异常。异常在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()行,重新部署应用程序,然后重新加载/Erroneous,则浏览器中将看不到任何内容。我不知道实际发生了什么,但是我想out.close()阻止了错误处理。

[使用Netbeans 7.4在Tomcat 7.0.50和Java EE 6上进行了测试。

© www.soinside.com 2019 - 2024. All rights reserved.