Hay que llamar.close() en HttpServletResponse.getOutputStream ()/.getWriter()?


No pude encontrar una respuesta autorizada a esto con un poco de Googleo. En Java servlets, se puede acceder al cuerpo de respuesta a través de response.getOutputStream () o response.getWriter (). Hay que llamar .close () en esta secuencia después de haber sido escrita?

Por un lado, está la exhortación blochiana de cerrar siempre las corrientes de salida. Por otro lado, no creo que en este caso haya un recurso subyacente que necesite ser cerrado. Se gestiona la apertura / cierre de sockets en el nivel HTTP, para permitir cosas como conexiones persistentes y tales.

Author: Steven Huwig, 2009-07-21

5 answers

Normalmente no debes cerrar la secuencia. El contenedor servlet cerrará automáticamente la corriente después de que el servlet haya terminado de funcionar como parte del ciclo de vida de la solicitud de servlet.

Por ejemplo, si cerrara la secuencia, no estaría disponible si implementara un filtro .

Habiendo dicho todo eso, si lo cierras nada malo sucederá mientras no intentes usarlo de nuevo.

EDITAR: otro filtro enlace

EDIT2: adrian.tarau tiene razón en que si desea alterar la respuesta después de que el servlet haya hecho lo suyo, debe crear un wrapper que extienda HttpServletResponseWrapper y almacene en búfer la salida. Esto es para evitar que la salida vaya directamente al cliente, pero también le permite proteger si el servlet cierra el flujo, según este extracto (énfasis mío):

Un filtro que modifica una respuesta debe normalmente captura la respuesta antes de ella se devuelve al cliente. El camino a hacer esto es pasar el servlet que genera la respuesta un sustituto flujo. La corriente stand-in evita el servlet de cerrar el original flujo de respuesta cuando se completa y permite que el filtro modifique el respuesta de Servlet.

Artículo

Uno puede inferir de ese artículo oficial de Sun que cerrar el outputstream de un servlet es algo que es normal, pero no es obligatorio.

 82
Author: Nemi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-09-03 21:02:57

La regla general de ellos es esta: si abriste la corriente, entonces deberías cerrarla. Si no lo hiciste, no deberías. Asegúrate de que el código sea simétrico.

En el caso de HttpServletResponse, es un poco menos claro, ya que no es obvio si llamar a getOutputStream() es una operación que abre la secuencia. El Javadoc solo dice que "Returns a ServletOutputStream"; de manera similar para getWriter(). De cualquier manera, lo que está claro es que HttpServletResponse "posee" el stream/writer, y él (o el contenedor) es responsable de cerrarlo nuevamente.

So para responder a su pregunta-no, no debe cerrar la corriente en este caso. El contenedor debe hacer eso, y si llegas allí antes, te arriesgas a introducir errores sutiles en tu aplicación.

 59
Author: skaffman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-21 15:18:00

Si hay alguna posibilidad de que el filtro pueda ser llamado en un recurso 'incluido', definitivamente debe no cerrar la secuencia. Esto causará que el recurso incluido falle con una excepción 'stream closed'.

 4
Author: Skip Head,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-10-15 17:58:54

Debe cerrar la secuencia, el código es más limpio ya que invoca getOutputStream() y la secuencia no se le pasa como parámetro, cuando generalmente solo la usa y no intenta cerrarla. La API de Servlet no indica que si el flujo de salida se puede cerrar o no debe cerrarse, en este caso puede cerrar el flujo de forma segura, cualquier contenedor ahí fuera se encarga de cerrar el flujo si no fue cerrado por el servlet.

Aquí está el método close () en Jetty, se cierran la corriente si no está cerrada.

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

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

        super.close();
    }

También como desarrollador de un Filtro no debe presumir que el flujo de salida no está cerrado, siempre debe pasar otro flujo de salida si desea alterar el contenido después de que el servlet haya hecho su trabajo.

EDITAR : Siempre estoy cerrando la transmisión y no tuve ningún problema con Tomcat/Jetty. No creo que debas tener problemas con ningún contenedor, viejo o nuevo.

 3
Author: adrian.tarau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-21 15:24:10

Otro argumento en contra de cerrar el OutputStream. Mira este servlet. Lanza una excepción. La excepción se asigna en la web.xml a un error 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();
    }
  }
}

La web.archivo xml contiene:

<?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>

Y el 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>

Cuando carga /Erroneous en el navegador, verá la página de error que muestra "Un error". Pero si des-comentas la línea out.close() en el servlet anterior, redistribuyes la aplicación y recargas /Erroneous no verás nada en el navegador. No tengo ni idea de lo que en realidad está sucediendo, pero supongo que out.close() evita el manejo de errores.

Probado con Tomcat 7.0.50, Java EE 6 usando Netbeans 7.4.

 2
Author: user1872904,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-19 15:42:38