Si dovrebbe chiamare .close () su HttpServletResponse.getOutputStream () /. GetWriter ()?

Non sono riuscito a trovare una risposta autorevole a questo con un po ‘di Google. Nei servlet Java, è ansible accedere al corpo della risposta tramite response.getOutputStream () o response.getWriter (). Si dovrebbe chiamare .close () su questo stream dopo averlo scritto?

Da un lato, c’è l’esortazione blochiana di chiudere sempre i flussi di output. D’altro canto, non penso che in questo caso ci sia una risorsa sottostante che deve essere chiusa. L’apertura / chiusura dei socket è gestita a livello HTTP, per consentire cose come connessioni persistenti e così via.

Normalmente non si dovrebbe chiudere il stream. Il contenitore servlet chiuderà automaticamente il stream dopo che il servlet ha terminato l’esecuzione come parte del ciclo di vita della richiesta del servlet.

Ad esempio, se hai chiuso il stream non sarebbe disponibile se hai implementato un filtro .

Detto questo, se lo chiudi, non accadrà nulla di male finché non proverai a usarlo di nuovo.

EDIT: un altro collegamento al filtro

EDIT2: adrian.tarau è corretto nel fatto che se si desidera modificare la risposta dopo che il servlet ha fatto la sua azione, è necessario creare un wrapper che estenda HttpServletResponseWrapper e buffer l’output. Questo serve a mantenere l’output di andare direttamente al client ma consente anche di proteggere se il servlet chiude il stream, come da questo estratto (enfasi mia):

Un filtro che modifica una risposta deve in genere acquisire la risposta prima che venga restituita al client. Il modo per farlo è passare il servlet che genera la risposta un stream stand-in. Lo stream di supporto impedisce al servlet di chiudere il stream di risposta originale quando viene completato e consente al filtro di modificare la risposta del servlet.

Articolo

Si può dedurre da quell’articolo ufficiale di Sun che chiudere l’outputstream da un servlet è qualcosa che è un evento normale, ma non è obbligatorio.

La regola generale è questa: se hai aperto il stream, dovresti chiuderlo. Se non l’hai fatto, non dovresti. Assicurati che il codice sia simmetrico.

Nel caso di HttpServletResponse , è un po ‘meno chiaro, dal momento che non è ovvio se chiamare getOutputStream() sia un’operazione che apre il stream. Javadoc dice semplicemente che ” Returns a ServletOutputStream “; allo stesso modo per getWriter() . In entrambi i casi, ciò che è chiaro è che HttpServletResponse “possiede” lo stream / writer e che (o il contenitore) è responsabile della sua chiusura.

Quindi, per rispondere alla tua domanda – no, non devi chiudere lo stream in questo caso. Il contenitore deve farlo, e se vieni lì prima, rischi di introdurre dei bug sottili nella tua applicazione.

Se esiste la possibilità che il filtro venga richiamato su una risorsa “inclusa”, non devi assolutamente chiudere il stream. Ciò causerà il fallimento della risorsa inclusa con un’eccezione ‘stream chiuso’.

Dovresti chiudere lo stream, il codice è più pulito poiché invochi getOutputStream () e il stream non ti viene passato come parametro, quando di solito lo usi e non provi a chiuderlo. L’API Servlet non afferma che se il stream di output può essere chiuso o non deve essere chiuso, in questo caso è ansible chiudere il stream in sicurezza, qualsiasi contenitore in uscita si occupa di chiudere il stream se non è stato chiuso dal servlet.

Ecco il metodo close () in Jetty, chiudono lo stream se non è chiuso.

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

Inoltre, come sviluppatore di un filtro non si dovrebbe presumere che OutputStream non sia chiuso, si dovrebbe sempre passare un altro OutputStream se si desidera modificare il contenuto dopo che il servlet ha fatto il suo lavoro.

EDIT: Sto sempre chiudendo il stream e non ho avuto alcun problema con Tomcat / Jetty. Non penso che dovresti avere problemi con nessun contenitore, vecchio o nuovo.

Un altro argomento contro la chiusura di OutputStream . Guarda questo servlet. Genera un’eccezione. L’eccezione è mappata nel web.xml a un JSP di errore:

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

Il file web.xml contiene:

 < ?xml version="1.0" encoding="UTF-8"?>    30    java.io.IOException /error.jsp   

E l’error.jsp:

 < %@page contentType="text/html" pageEncoding="UTF-8" isErrorPage="true"%> < !DOCTYPE html>    Error Page   

< %= exception.getMessage()%>

Quando si carica /Erroneous nel browser, viene visualizzata la pagina di errore con “Errore”. Ma se out.close() la out.close() nel servlet di cui sopra, ridistribuisci l’applicazione e ricarica /Erroneous non vedrai nulla nel browser. Non ho idea di cosa stia realmente succedendo, ma suppongo che out.close() impedisca la gestione degli errori.

Testato con Tomcat 7.0.50, Java EE 6 utilizzando Netbeans 7.4.