可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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 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
回答1:
This article has the complete (and brief) source code for a ServletFilter that automatically compresses on the fly.
回答2:
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).
回答3:
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.
回答4:
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.
回答5:
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.
回答6:
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.
回答7:
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!