102 votes

Faut-il appeler .close () sur HttpServletResponse.getOutputStream () /. GetWriter ()?

Je ne pouvais pas trouver une réponse ferme à cette avec quelques recherches sur Google. Dans les servlets Java, on peut accéder à la réponse du corps par l'intermédiaire de réponse.getOutputStream() ou de la réponse.getWriter(). Doit-on l'appeler .close() sur ce cours d'eau après qu'il a été écrit?

D'une part, il y a le Blochian exhortation à toujours fermer les flux de sortie. D'autre part, je ne pense pas que, dans ce cas, il est une ressource sous-jacente qui doit être fermé. L'ouverture/fermeture de sockets est géré au niveau HTTP, afin de permettre des choses comme des connexions persistantes.

100voto

Nemi Points 1758

Normalement, vous ne devez pas fermer le flux de données. Le conteneur de servlet va automatiquement fermer le flux de données après la servlet est terminée en cours d'exécution dans le cadre de la servlet demande de cycle de vie.

Par exemple, si vous avez fermé le flux, il ne serait pas disponible si vous avez mis en place un Filtre.

Ayant dit tout cela, si vous ne la fermez rien de mauvais va se passer tant que vous n'essayez pas de l'utiliser à nouveau.

EDIT: un autre filtre de lien

EDIT2: adrian.tarau est correct que si vous voulez modifier la réponse après la servlet a fait sa chose, vous devez créer un wrapper de l'extension de HttpServletResponseWrapper et le tampon de sortie. C'est pour la sortie de passer directement au client, mais vous permet également de vous protéger si le servlet ferme le flux, comme par cet extrait (l'emphase est mienne):

Un filtre qui modifie la réponse généralement capturer la réponse avant qu'il est retourné au client. La façon de ce faire est de passer la servlet qui génère la réponse à flux de données. Le flux empêche la servlet à partir de la fermeture de l'original flux de réponse lorsqu'elle est terminée et permet au filtre de modifier la servlet réponse.

L'Article

On peut déduire de ce fonctionnaire, le Soleil de l'article que la fermeture de la outputstream à partir d'une servlet est quelque chose qui est tout à fait normal, mais n'est pas obligatoire.

87voto

skaffman Points 197885

La règle générale de ceci: si vous avez ouvert le flux, alors vous devriez la fermer. Si vous n'avez pas, vous ne devriez pas. Assurez-vous que le code est symétrique.

Dans le cas d' HttpServletResponse, c'est un peu moins claire, car il n'est pas évident, si l'appelant getOutputStream() est une opération qui ouvre le flux. La Javadoc juste dit qu'il "Returns a ServletOutputStream"; de même pour getWriter(). De toute façon, ce qui est clair, c'est qu' HttpServletResponse "propriétaire" du flux de l'écrivain, et il (ou conteneur) est responsable de la fermeture de nouveau.

Donc, pour répondre à votre question, non, vous ne devez pas fermer le flux de données dans ce cas. Le conteneur doit le faire, et si vous en arrivez là avant, vous risquez d'introduire des bogues dans votre application.

5voto

Skip Head Points 4062

S'il y a une chance que le filtre soit appelé sur une ressource 'incluse', vous ne devez absolument pas fermer le flux. Cela entraînerait l'échec de la ressource incluse avec une exception 'flux fermé'.

5voto

user1872904 Points 33

Un autre argument contre la fermeture de l' OutputStream. Regardez cette servlet. Elle lève une exception. L'exception est représentée dans la web.xml à une erreur 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();
    }
  }
}

L'web.xml le fichier contient:

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

Et l'erreur.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>

Lorsque vous chargez /Erroneous dans le navigateur, vous voyez la page d'erreur qui affiche "Une erreur". Mais si vous dé-commentez l' out.close() ligne au-dessus de la servlet, redéployer de l'application, et de recharger /Erroneous vous verrez rien dans le navigateur. Je n'ai aucune idée de ce qui se passe réellement, mais je suppose que c' out.close() empêche l'erreur de manipulation.

Testé avec Tomcat 7.0.50, Java EE 6 à l'aide de Netbeans 7.4.

4voto

adrian.tarau Points 2023

Vous devez fermer le flux de données, le code est plus propre depuis que vous appelez getOutputStream() et le flux n'est pas transmis à vous en tant que paramètre, généralement lorsque vous venez de l'utiliser et de ne pas tenter de le fermer. La Servlet API n'a pas d'états que si le flux de sortie peut être fermé et ne doit pas être fermé, dans ce cas, vous pouvez fermer le flux de données, un conteneur de là se charge de fermer le flux, si elle n'a pas été fermé par la servlet.

Voici la méthode close() de la Jetée, ils fermer le flux de données si elle n'est pas fermée.

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

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

        super.close();
    }

Aussi en tant que développeur d'un Filtre vous ne devez pas présumer que l'OutputStream n'est pas fermé, vous devez toujours passer à un autre OutputStream si vous voulez modifier le contenu après la servlet a fait son travail.

EDIT : je suis toujours à la fermeture du ruisseau et je n'ai pas eu de problèmes avec Tomcat/Jetty. Je ne pense pas que vous devriez avoir aucun problème avec n'importe quel conteneur, anciennes ou nouvelles.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X