开发者

Serve Gzipped content with Java Servlets

I was wondering if there was an easy way to serve GZipped content with Java Servlets. I already ha开发者_Go百科ve the app up and running so the modifications needed should be too heavy.

I have access to the response object just at the end of the doPost/doGet method, so I'm looking for something like

response.setGzip(true);

It doesn't have to be that easy but it would be ideal.

Thanks a lot


Depending on your container, the container will most likely do this for you. It may do it automatically, or you might need to manually configure it to do it for you. The advantage of this method is zero code changes. And, again, depending on container, you can conditionally enable/disable the compression based on where the request comes from or source browser.

For Tomcat, have a look at the compression attribute on the HTTP config pages (v5.5, v6.0).


There are basically 2 ways:

  • Configure it in the appserver. In for example Tomcat you just need to set the compression attribute of the Connector in conf/server.xml to on.
  • Wrap the response.getOutputStream() in a new GzipOutputStream() and write to it instead.

The first way affects the whole webapp, but this really shouldn't hurt, it's almost zero effort and a big favour for performance. And, more importantingly, as opposed to the second way it actually checks the request headers if the client supports Gzip before using it. When you go for the 2nd way headlessly, then about 10% of the world wide web users wouldn't be able to access your webapplication. This is really not an oneliner task.

You can find here an advanced example of a FileServlet which supports under each Gzip and checks that based on the request headers. You may get new insights out of it.


Look at GzipOutputStream class. Something like this:

response.setContentType(...)
GzipOutputStream os = new GzipOutputStream(response.getOutputStream);
//write to os
Writer writer = new PrintWriter(os);

Then use writer like you do usually.


This's what I used while learning about servlets. Maybe not usefully, but working!!! Laid below code into public class GZIPEncodingServlet extends HttpServlet {...}

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    if (req.getHeader("Accept-Encoding").contains("gzip")) {

        // 'try' block need for closing of stream, of course we can use 'close()' method for our 'PrintWriter' too
        try (PrintWriter printWriter = new PrintWriter(new GZIPOutputStream(resp.getOutputStream()))) {

            resp.setHeader("Content-Encoding", "gzip"); // Client must understood what we're sending him
            printWriter.write("Hello world from gzip encoded html"); // What is sending?
        }

    } else {
        resp.getWriter().write("Can't encode html to gzip :(");
    }

}


If you really, really don't want to fiddle with the Java code any more, you could also consider hooking an Apache server in front of your servlet container.

If you have a lot of static content, this could actually improve performance for you, as the Apache will be a bit faster for static pages than any servlet container. So you'd configure it to only delegate servlet requests to your servlet container on localhost.

Apache has handy built-in options for compressing output. I don't remember how to set them, but it's easy and versatile. It negotiates with browsers about what they can handle, and so on. In case of doubt, Apache will generally be more savvy and up-to-date on compression methods than any Java container.


If you are on Tomcat, the connector can do compression for you. This is my configuration,

<Connector port="8000"
 compression="on" 
 compressionMinSize="1024" 
 compressableMimeType="text/html,text/xml" 
 ...
/> 

If you run Apache httpd in front of Tomcat, you should use mod_gzip, which does a much better job.


Just wanted to let you know what I ended doing.

I made a wrapper of the request class that looks like this:

public class GzippedResponse extends HttpServletResponseWrapper{

  private PrintWriter pw;

  private GzippedResponse(HttpServletResponse response){
    super(response);
    try{
      pw = new PrintWriter(new GZIPOutputStream(response.getOutputStream()));
    }catch(Exception e){
      throw new ApiInternalException("Failed to create a Gzipped Response", e);
    }
  }

  public static GzippedResponse wrap(HttpServletResponse response){
    return new GzippedResponse(response);
  }

  @Override
  public PrintWriter getWriter() throws IOException {
    return pw;
  }  
}

And then on my BaseAction, which is basically a TemplateMethod for other "Actions" I wrap the response like this:

if(supportsCompression(request)){
  response.setHeader("Content-Encoding", "gzip");
  response = GzippedResponse.wrap(response);
}
action.macroExecute(request,response);

I think its clean enough. If you find something that can be improved, please let me know. Thanks everybody for the answers!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜