Should one call .close() on HttpServletResponse.getOutputStream()/.getWriter()?

JavaServletsOutputstream

Java Problem Overview


In Java Servlets, one can access the response body via response.getOutputStream() or response.getWriter(). Should one call .close() on this OutputStream after it has been written to?

On the one hand, there is the Blochian exhortation to always close OutputStreams. On the other hand, I don't think that in this case there is an underlying resource that needs to be closed. The opening/closing of sockets is managed at the HTTP level, to allow things like persistent connections and such.

Java Solutions


Solution 1 - Java

Normally you should not close the stream. The servlet container will automatically close the stream after the servlet is finished running as part of the servlet request life-cycle.

For instance, if you closed the stream it would not be available if you implemented a Filter.

Having said all that, if you do close it nothing bad will happen as long as you don't try to use it again.

EDIT: another filter link

EDIT2: adrian.tarau is correct in that if you want to alter the response after the servlet has done its thing you should create a wrapper extending HttpServletResponseWrapper and buffer the output. This is to keep the output from going directly to the client but also allows you to protect if the servlet closes the stream, as per this excerpt (emphasis mine): > A filter that modifies a response must > usually capture the response before it > is returned to the client. The way to > do this is to pass the servlet that > generates the response a stand-in > stream. The stand-in stream prevents > the servlet from closing the original > response stream when it completes and > allows the filter to modify the > servlet's response.

Article

One can infer from that official Sun article that closing the OutputStream from a servlet is something that is a normal occurrence, but is not mandatory.

Solution 2 - Java

The general rule of them is this: if you opened the stream, then you should close it. If you didn't, you shouldn't. Make sure the code is symmetric.

In the case of HttpServletResponse, it's a bit less clear cut, since it's not obvious if calling getOutputStream() is an operation that opens the stream. The Javadoc just says that it "Returns a ServletOutputStream"; similarly for getWriter(). Either way, what is clear is that HttpServletResponse "owns" the stream/writer, and it (or the container) is responsible for closing it again.

So to answer your question - no, you should not close the stream in this case. The container must do that, and if you get in there before it, you risk introducing subtle bugs in your application.

Solution 3 - Java

If there is any chance the filter might be called on an 'included' resource, you should definitely not close the stream. This will cause the including resource to fail with a 'stream closed' exception.

Solution 4 - Java

You should close the stream, the code is cleaner since you invoke getOutputStream() and the stream is not passed to you as a parameter, when usually you just use it and don't attempt to close it. The Servlet API doesn't states that if the output stream can be closed or must not be closed, in this case you can safely close the stream, any container out there takes care of closing the stream if it was not closed by the servlet.

Here is the close() method in Jetty, they close the stream if it not closed.

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

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

        super.close();
    }

Also as a developer of a Filter you should not presume that the OutputStream is not closed, you should always pass another OutputStream if you want to alter the content after the servlet has done its job.

EDIT : I'm always closing the stream and I didn't had any problems with Tomcat/Jetty. I don't think you should have any problems with any container, old or new.

Solution 5 - Java

Another argument against closing the OutputStream. Look at this servlet. It throws an exception. The exception is mapped in the web.xml to an error 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();
    }
  }
}

The web.xml file contains:

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

And the 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>

When you load /Erroneous in the browser you see the error page displaying "An error". But if you un-comment the out.close() line in the above servlet, redeploy de application, and reload /Erroneous you’ll see nothing in the browser. I have no clue about what is actually happening, but I guess that out.close() prevents the error handling.

Tested with Tomcat 7.0.50, Java EE 6 using Netbeans 7.4.

Solution 6 - Java

If you're using Spring with Spring Security, you should not close the stream or writer.

Stream returned from ServletResponse.getOutputStream() or writer returned from ServletResponse.getWriter() will commit the response upon closing. Committing the response, as explained here, means that http status and headers become immutable and Spring framework will not be able to adjust http status even if exception gets thrown during serving this request.

An instance of OnCommittedResponseWrapper class is used as implementation of ServletResponse and here's the code responsible for this behavior (check javadoc as well).

Consider the following example controller:

@RestController
public class MyController {
    @RequestMapping(method = RequestMethod.POST, value = "/blah")
    public void entrypoint(ServletRequest request, ServletResponse response) throws IOException {
        try (var writer = response.getWriter()) {
            throw new RuntimeException("Something bad happened here");
        }
    }

When the exception is thrown, the first thing that happens is a call to writer.close() that'll freeze response http status to its default value 200.

Only after that the exception will start propagating from this controller to Spring error handlers. Spring error handlers will not be able to change the status to 500 because the response was committed already and so the status will remain 200.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSteven HuwigView Question on Stackoverflow
Solution 1 - JavaNemiView Answer on Stackoverflow
Solution 2 - JavaskaffmanView Answer on Stackoverflow
Solution 3 - JavaSkip HeadView Answer on Stackoverflow
Solution 4 - Javaadrian.tarauView Answer on Stackoverflow
Solution 5 - Javauser1872904View Answer on Stackoverflow
Solution 6 - JavaMikeView Answer on Stackoverflow