I was wondering if there was an easy way to serve GZipped content with Java Servlets. I already have the app up and running so the modifications needed should be to
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!
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.
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 :(");
}
}
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.
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).
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.