Setting the Content-Length header from a Java Servlet

If you have run the test mentioned on the previous page to determine whether your Servlet is compatible with keep-alive connections and found that it isn't, then a solution is to manually set the HTTP Content-Length beader from your Servlet to the number of bytes that your Servlet is going to output. In a typical case, you won't actually know this in advance. So the easiest solution is to write all your servlet's output into a temporary byte buffer, whose length you can then measure before sending its contents as the final output.

A handy feature of the Java IO framework is its modular approach to streams. We can write our output to a buffer just as easily as if we were writing it to the servlet output stream. Where before we would have done this:

public void doGet(HttpServletRequest req, HttpServletResponse res)
    throws ServletException, IOException {
  PrintWriter pw = res.getWriter();
    // ... output page to pw...

instead, we declare pw as writing to a PrintWriter wrapped around our buffer:

private static final ENCODING = "UTF-8";

public void doGet(HttpServletRequest req, HttpServletResponse res)
      throws ServletException, IOException {
  ByteArrayOutputStream bout = new ByteArrayOutputStream(8192);
  PrintWriter pw = new PrintWriter(new OutputStreamWriter(bout, ENCODING ));
  // ... output page to pw ...

Note that we set the character encoding. Since we're now writing to our own PrintWriter, it could have a different character encoding to the default one used by the servlet's writer. It's safer not to rely on the default encoding, and just specify an encoding. When we set the content length header, we also set the Content-Encoding header. That way, the client will always be told how we've encoded the page and will hopefully display it correctly. So the final part of our doGet() method looks as follows:

res.setHeader("Content-Encoding", ENCODING);

It so happens that HttpServletResponse has the handy method setContentLength() which we can use, but essentially all it's doing is setting the ContentLength header. For the character encoding, there's no such method, so we set the header "manually" using setHeader().

Another difference is where we write the byte array to. Since we've now turned the characters into bytes via our own PrintWriter and OutputStreamWriter, we call res.getOutputStream(). This tells us the place to send Servlet output when we want to send "raw data" rather than character/textual data.

If you enjoy this Java programming article, please share with friends and colleagues. Follow the author on Twitter for the latest news and rants.

Editorial page content written by Neil Coffey. Copyright © Javamex UK 2021. All rights reserved.