Je n'ai pas pu trouver de réponse faisant autorité à cela avec des recherches sur Google. Dans les servlets Java, on peut accéder au corps de la réponse via response.getOutputStream () ou response.getWriter (). Doit-on appeler .close () sur ce flux une fois qu'il a été écrit?
D'une part, il y a l'exhortation blochienne à toujours fermer les flux de sortie. D'un autre côté, je ne pense pas que dans ce cas il y ait une ressource sous-jacente qui doit être fermée. L'ouverture/fermeture des sockets est gérée au niveau HTTP, pour permettre des choses comme les connexions persistantes et autres.
Normalement, vous ne devez pas fermer le flux. Le conteneur de servlet fermera automatiquement le flux une fois que le servlet aura fini de fonctionner dans le cadre du cycle de vie de la demande de servlet.
Par exemple, si vous fermiez le flux, il ne serait pas disponible si vous implémentiez un Filter .
Cela dit, si vous le fermez, rien de mauvais ne se produira tant que vous n'essayez pas de le réutiliser.
EDIT: n autre lien de filtre
EDIT2: adrian.tarau a raison, si vous voulez modifier la réponse une fois que le servlet a fait son travail, vous devez créer un wrapper étendant HttpServletResponseWrapper et mettre en mémoire tampon la sortie. C'est pour empêcher la sortie d'aller directement au client, mais vous permet également de protéger si le servlet ferme le flux, selon cet extrait (accentuation du mien):
Un filtre qui modifie une réponse doit généralement capturer la réponse avant qu'elle ne soit renvoyée au client. La façon de procéder consiste à transmettre le servlet qui génère la réponse à un flux permanent. Le flux stand-in empêche le servlet de fermer le flux de réponse d'origine lorsqu'il se termine et permet au filtre de modifier la réponse du servlet.
On peut déduire de cet article officiel de Sun que la fermeture du flux de sortie d'un servlet est quelque chose de normal, mais pas obligatoire.
La règle générale est la suivante: si vous avez ouvert le flux, vous devez le fermer. Sinon, vous ne devriez pas. Assurez-vous que le code est symétrique.
Dans le cas de HttpServletResponse
, c'est un peu moins clair, car ce n'est pas évident si appeler getOutputStream()
est une opération qui ouvre le flux. Le Javadoc dit simplement qu'il "Returns a ServletOutputStream
"; de même pour getWriter()
. Quoi qu'il en soit, ce qui est clair, c'est que HttpServletResponse
"possède" le flux/écrivain, et qu'il (ou le conteneur) est responsable de le refermer.
Donc, pour répondre à votre question - non, vous ne devez pas fermer le flux dans ce cas. Le conteneur doit le faire, et si vous y entrez avant, vous risquez d'introduire des bogues subtils dans votre application.
S'il y a une chance que le filtre soit appelé sur une ressource "incluse", vous devez certainement pas fermer le flux. Cela entraînera l'échec de la ressource incluse avec une exception "flux fermé".
Vous devez fermer le flux, le code est plus propre puisque vous appelez getOutputStream () et le flux ne vous est pas transmis en tant que paramètre, alors que vous l'utilisez généralement 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é, tout conteneur se charge de fermer le flux s'il n'a pas été fermé par le servlet.
Voici la méthode close () dans Jetty, ils ferment le flux 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();
}
De plus, en tant que développeur d'un filtre, vous ne devez pas présumer que OutputStream n'est pas fermé, vous devez toujours transmettre un autre OutputStream si vous souhaitez modifier le contenu une fois que la 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 de problèmes avec un conteneur, ancien ou nouveau.
Un autre argument contre la fermeture de OutputStream
. Regardez cette servlet. Cela 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();
}
}
}
Le fichier web.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 le 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>
Lorsque vous chargez /Erroneous
Dans le navigateur, vous voyez la page d'erreur affichant "Une erreur". Mais si vous décommentez la ligne out.close()
dans le servlet ci-dessus, redéployez l'application et rechargez /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 gestion des erreurs.
Testé avec Tomcat 7.0.50, Java EE 6 utilisant Netbeans 7.4.