Doit-on l'appeler.close () on HttpServletResponse.getOutputStream ()/.getWriter()?

Je n'ai pas pu trouver de réponse fiable avec un peu de Googling. Dans les servlets Java, on peut accéder au corps de la réponse via la réponse.getOutputStream () ou response.getWriter(). Doit-on l'appeler .close() sur ce cours d'eau après qu'il a été écrit?

d'un côté, il y a l'exhortation Blochienne de 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, pour autoriser des choses comme les connexions persistantes et autres.

80
demandé sur Steven Huwig 2009-07-21 17:27:53

5 réponses

normalement, vous ne devriez pas fermer le ruisseau. Le conteneur de servlet fermera automatiquement le flux après que le servlet est terminé en cours d'exécution dans le cadre du cycle de vie de la requête de servlet.

par exemple, si vous avez fermé le flux, il ne serait pas disponible si vous avez mis en œuvre un filtre .

après avoir dit tout cela, si vous le fermez, rien de mal n'arrivera tant que vous n'essaierez pas de l'utiliser à nouveau.

EDIT: un autre filtre lien

EDIT2: adrian.tarau a raison en ce que si vous voulez modifier la réponse après que le servlet a fait sa chose, vous devez créer un wrapper extending HttpServletResponseWrapper et buffer la sortie. C'est pour empêcher la sortie de passer directement au client mais aussi pour vous protéger si le servlet ferme le flux, comme dans cet extrait (emphasis mine):

A filtre qui modifie la réponse habituellement saisir la réponse avant est retourné au client. La façon de faire ceci est de passer le servlet que génère la réponse à flux. Le flux empêche le service de fermeture de l'original flux de réponse lorsqu'il est terminé et permet au filtre de modifier la réponse de servlet.

Article

On peut déduire de cet article officiel de Sun que la fermeture de la sortie d'un servlet est quelque chose qui est un événement normal, mais n'est pas obligatoire.

82
répondu Nemi 2009-09-03 21:02:57

la règle générale est la suivante: si vous ouvrez le ruisseau, vous devez le fermer. Si tu ne l'as pas fait, tu ne devrais pas. Assurez-vous que le code est symétrique.

dans le cas de HttpServletResponse , c'est un peu moins clair, car il n'est pas évident si l'appel getOutputStream() est une opération qui ouvre le flux. Le Javadoc dit juste qu'il" Returns a ServletOutputStream "; de même pour getWriter() . Quoi qu'il en soit, ce qui est clair est que HttpServletResponse "possède" le stream / writer, et il (ou le conteneur) est responsable de la fermeture de nouveau.

donc pour répondre à votre question - non, vous ne devriez pas fermer le ruisseau dans ce cas. Le conteneur doit le faire, et si vous en arrivez là avant, vous risquez d'introduire des bogues dans votre application.

59
répondu skaffman 2009-07-21 15:18:00

S'il y a une chance que le filtre puisse être appelé sur une ressource" incluse", vous devez certainement et non fermer le flux. Cela causera l'échec de la ressource including avec une exception "stream closed".

4
répondu Skip Head 2010-10-15 17:58:54

vous devez fermer le flux, le code est plus propre puisque vous invoquez getOutputStream() et le flux ne vous est pas passé en paramètre, alors que d'habitude vous l'utilisez simplement et n'essayez pas de le fermer. L'API Servlet N'indique pas que si le flux de sortie peut être fermé ou ne doit pas l'être, dans ce cas vous pouvez fermer le flux en toute sécurité, n'importe quel conteneur là-bas prend soin de fermer le flux s'il n'était pas fermé par le servlet.

Voici la méthode close() à Jetty, ils ferment le ruisseau s'il n'est pas fermé.

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 le flux sortant n'est pas fermé, vous devez toujours passer un autre flux sortant si vous voulez modifier le contenu après que le servlet a fait son travail.

EDIT: je ferme toujours le flux et je n'ai eu aucun problème avec Tomcat/Jetty. Je ne pense pas que vous devriez avoir des problèmes avec n'importe quel conteneur, vieux ou neuf.

3
répondu adrian.tarau 2009-07-21 15:24:10

un autre argument contre la fermeture du OutputStream . Regardez cette servlet. Elle lève une exception. L'exception est mappée dans le 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();
    }
  }
}

sur Le web.le fichier xml 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 affichant "une erreur". Mais si vous dés-commentez la ligne out.close() dans le servlet ci-dessus, redéployer de application, et recharger /Erroneous vous ne verrez rien dans le navigateur. Je n'ai aucune idée de ce qui se passe réellement, mais je suppose que out.close() empêche la manipulation des erreurs.

Testé avec Tomcat 7.0.50, Java EE 6 avec Netbeans 7.4.

2
répondu user1872904 2014-02-19 15:42:38