java servlets outputstream

java - ¿Debería uno llamar a.close() en HttpServletResponse.getOutputStream()/. GetWriter()?



servlets (5)

No pude encontrar una respuesta autorizada a esto con Google. En los servlets de Java, uno puede acceder al cuerpo de respuesta a través de response.getOutputStream () o response.getWriter (). ¿Debería uno llamar a .close () en esta secuencia después de haber sido escrita?

Por un lado, está la exhortación de Bloch a cerrar siempre los flujos de salida. Por otro lado, no creo que en este caso haya un recurso subyacente que deba cerrarse. La apertura / cierre de sockets se gestiona a nivel HTTP, para permitir cosas como conexiones persistentes y demás.


Debe cerrar la secuencia, el código es más claro ya que invoca getOutputStream () y la transmisión no se le pasa como parámetro, cuando generalmente solo la usa y no intenta cerrarla. La API de Servlet no establece que si la secuencia de salida se puede cerrar o no se debe cerrar, en este caso puede cerrar la transmisión de manera segura, cualquier contenedor que se encuentre allí se ocupa de cerrar la transmisión si el servlet no la cerró.

Aquí está el método close () en Jetty, cierran la transmisión si no se cierra.

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

Además, como desarrollador de un filtro, no debe presumir que OutputStream no está cerrado, siempre debe pasar otro OutputStream si desea modificar el contenido una vez 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 tengas problemas con ningún contenedor, viejo o nuevo.


La regla general de ellos es esta: si abriste el flujo, entonces debes cerrarlo. 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 transmisión. El Javadoc simplemente dice que " Returns a ServletOutputStream "; del mismo modo para getWriter() . De cualquier manera, lo que está claro es que HttpServletResponse "posee" el flujo / escritor, y él (o el contenedor) es responsable de cerrarlo nuevamente.

Entonces, para responder a su pregunta, no, no debe cerrar la transmisión en este caso. El contenedor debe hacer eso, y si ingresas antes, te arriesgas a introducir errores sutiles en tu aplicación.


Normalmente no deberías cerrar la transmisión. El contenedor de servlets cerrará automáticamente la secuencia después de que el servlet haya terminado de ejecutarse como parte del ciclo de vida de la solicitud de servlet.

Por ejemplo, si cerró la transmisión, no estaría disponible si implementó un Filter .

Habiendo dicho todo eso, si lo cierras no pasará nada malo siempre y cuando no intentes usarlo de nuevo.

EDITAR: otro enlace de filtro

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 contenedor que extienda HttpServletResponseWrapper y almacenar la salida. Esto es para evitar que la salida vaya directamente al cliente pero también le permite proteger si el servlet cierra la transmisión, según este extracto (el énfasis es mío):

Un filtro que modifica una respuesta generalmente debe capturar la respuesta antes de devolverla al cliente. La forma de hacerlo es pasar el servlet que genera la respuesta una secuencia de entrada. La secuencia de reserva impide que el servlet cierre la secuencia de respuesta original cuando se completa y permite que el filtro modifique la respuesta del servlet.

Article

Uno puede inferir de ese artículo oficial de Sun que el cierre de la salida de un servlet es algo que ocurre normalmente, pero que no es obligatorio.


Otro argumento contra el cierre de OutputStream . Mira este servlet. Lanza una excepción. La excepción se asigna en el web.xml a un JSP de error:

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(); } } }

El archivo web.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, ve la página de error que muestra "Un error". Pero si out.close() el comentario de la línea out.close() en el servlet anterior, out.close() desplegar la aplicación y vuelve a cargar /Erroneous , no verá nada en el navegador. No tengo ni idea de lo que está sucediendo en realidad, pero supongo que out.close() evita el manejo de errores.

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


Si existe la posibilidad de que el filtro sea llamado en un recurso ''incluido'', definitivamente no deberías cerrar la transmisión. Esto causará que el recurso incluido falle con una excepción ''secuencia cerrada''.