1、在tomcat的server.xml配置文件中,添加上背景颜色为绿色的配置,服务器就会自动压缩
<Connector port="80" maxHttpHeaderSize="8192" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" redirectPort="8443" acceptCount="100" connectionTimeout="20000" disableUploadTimeout="true" URIEncoding="utf-8" compression="on" compressionMinSize="2048" noCompressionUserAgents="gozilla, traviata" compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain" />
详细讲解:
1) compression="on" 打开压缩功能
2) compressionMinSize="2048" 启用压缩的输出内容大小,这里面默认设置为2KB
3) noCompressionUserAgents="gozilla, traviata" 对于以下的浏览器,不启用压缩
4) compressableMimeType="text/html,text/xml" 压缩类型(默认为text/html,text/xml,text/plain)
2、如果希望支持bzip2压缩,我的环境是apache cfx框架,自定义了一个跟GZIPOutInterceptor相似的拦截器,然后配置在接口的发布配置文件里。
详细介绍如下:
BZIPOutInterceptor代码如下:
import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.ResourceBundle; import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.cxf.common.i18n.BundleUtils; import org.apache.cxf.common.logging.LogUtils; import org.apache.cxf.helpers.CastUtils; import org.apache.cxf.helpers.HttpHeaderHelper; import org.apache.cxf.interceptor.Fault; import org.apache.cxf.interceptor.MessageSenderInterceptor; import org.apache.cxf.io.AbstractThresholdOutputStream; import org.apache.cxf.message.Exchange; import org.apache.cxf.message.Message; import org.apache.cxf.phase.AbstractPhaseInterceptor; import org.apache.cxf.phase.Phase; import org.apache.tools.bzip2.CBZip2OutputStream; /** * CXF interceptor that compresses outgoing messages using bzip and sets the * HTTP Content-Encoding header appropriately. An instance of this class should * be added as an out interceptor on clients that need to talk to a service that * accepts gzip-encoded requests or on a service that wants to be able to return * compressed responses. In server mode, the interceptor only compresses * responses if the client indicated (via an Accept-Encoding header on the * request) that it can understand them. To handle gzip-encoded input messages, * see {@link GZIPInInterceptor}. This interceptor supports a compression * {@link #threshold} (default 1kB) - messages smaller than this threshold will * not be compressed. To force compression of all messages, set the threshold to * 0. This class was originally based on one of the CXF samples * (configuration_interceptor). */ public class BZIPOutInterceptor extends AbstractPhaseInterceptor<Message> { /** * Enum giving the possible values for whether we should gzip a particular * message. */ public static enum UseBzip { NO, YES, FORCE } /** * regular expression that matches any encoding with a * q-value of 0 (or 0.0, 0.00, etc.). */ public static final Pattern ZERO_Q = Pattern.compile(";\\s*q=0(?:\\.0+)?$"); /** * regular expression which can split encodings */ public static final Pattern ENCODINGS = Pattern.compile("[,\\s]*,\\s*"); /** * Key under which we store the original output stream on the message, for * use by the ending interceptor. */ public static final String ORIGINAL_OUTPUT_STREAM_KEY = BZIPOutInterceptor.class.getName() + ".originalOutputStream"; /** * Key under which we store an indication of whether compression is * permitted or required, for use by the ending interceptor. */ public static final String USE_BZIP_KEY = BZIPOutInterceptor.class.getName() + ".useBzip"; /** * Key under which we store the name which should be used for the * content-encoding of the outgoing message. Typically "gzip" but may be * "x-gzip" if we are processing a response message and this is the name * given by the client in Accept-Encoding. */ public static final String BZIP_ENCODING_KEY = BZIPOutInterceptor.class.getName() + ".bzipEncoding"; public static final String SOAP_JMS_CONTENTENCODING = "SOAPJMS_contentEncoding"; private static final ResourceBundle BUNDLE = BundleUtils.getBundle(BZIPOutInterceptor.class); private static final Logger LOG = LogUtils.getL7dLogger(BZIPOutInterceptor.class); /** * Compression threshold in bytes - messages smaller than this will not be * compressed. */ private int threshold = 1024; private boolean force; public BZIPOutInterceptor() { super(Phase.PREPARE_SEND); addAfter(MessageSenderInterceptor.class.getName()); } public BZIPOutInterceptor(int threshold) { super(Phase.PREPARE_SEND); addAfter(MessageSenderInterceptor.class.getName()); this.threshold = threshold; } public void setThreshold(int threshold) { this.threshold = threshold; } public int getThreshold() { return threshold; } public void handleMessage(Message message) throws Fault { UseBzip use = bzipPermitted(message); if (use != UseBzip.NO) { // remember the original output stream, we will write compressed // data to this later OutputStream os = message.getContent(OutputStream.class); if (os == null) { return; } message.put(ORIGINAL_OUTPUT_STREAM_KEY, os); message.put(USE_BZIP_KEY, use); // new stream to cache the message BZipThresholdOutputStream cs = new BZipThresholdOutputStream(threshold, os, use == UseBzip.FORCE, message); message.setContent(OutputStream.class, cs); } } /** * Checks whether we can, cannot or must use gzip compression on this output * message. Gzip is always permitted if the message is a client request. If * the message is a server response we check the Accept-Encoding header of * the corresponding request message - with no Accept-Encoding we assume * that gzip is not permitted. For the full gory details, see <a * href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3">section * 14.3 of RFC 2616</a> (HTTP 1.1). * * @param message the outgoing message. * @return whether to attempt gzip compression for this message. * @throws Fault if the Accept-Encoding header does not allow any encoding * that we can support (identity, gzip or x-gzip). */ private UseBzip bzipPermitted(Message message) throws Fault { UseBzip permitted = UseBzip.NO; if (isRequestor(message)) { LOG.fine("Requestor role, so bzip enabled"); Object o = message.getContextualProperty(USE_BZIP_KEY); if (o instanceof UseBzip) { permitted = (UseBzip)o; } else if (o instanceof String) { permitted = UseBzip.valueOf((String)o); } else { permitted = force ? UseBzip.YES : UseBzip.NO; } message.put(BZIP_ENCODING_KEY, "bzip"); addHeader(message, "Accept-Encoding", "bzip;q=1.0, identity; q=0.5, *;q=0"); } else { LOG.fine("Response role, checking accept-encoding"); Exchange exchange = message.getExchange(); Message request = exchange.getInMessage(); Map<String, List<String>> requestHeaders = CastUtils.cast((Map<?, ?>)request .get(Message.PROTOCOL_HEADERS)); if (requestHeaders != null) { List<String> acceptEncodingHeader = CastUtils.cast(HttpHeaderHelper .getHeader(requestHeaders, HttpHeaderHelper.ACCEPT_ENCODING)); List<String> jmsEncodingHeader = CastUtils.cast(requestHeaders.get(SOAP_JMS_CONTENTENCODING)); if (jmsEncodingHeader != null && jmsEncodingHeader.contains("bzip")) { permitted = UseBzip.YES; message.put(BZIP_ENCODING_KEY, "bzip"); } if (acceptEncodingHeader != null) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("Accept-Encoding header: " + acceptEncodingHeader); } // Accept-Encoding is a comma separated list of entries, so // we split it into its component parts and build two // lists, one with all the "q=0" encodings and the other // with the rest (no q, or q=<non-zero>). List<String> zeros = new ArrayList<String>(3); List<String> nonZeros = new ArrayList<String>(3); for (String headerLine : acceptEncodingHeader) { String[] encodings = ENCODINGS.split(headerLine.trim()); for (String enc : encodings) { Matcher m = ZERO_Q.matcher(enc); if (m.find()) { zeros.add(enc.substring(0, m.start())); } else if (enc.indexOf(';') >= 0) { nonZeros.add(enc.substring(0, enc.indexOf(';'))); } else { nonZeros.add(enc); } } } // identity encoding is permitted if (a) it is not // specifically disabled by an identity;q=0 and (b) if // there is a *;q=0 then there is also an explicit // identity[;q=<non-zero>] // // [x-]gzip is permitted if (a) there is an explicit // [x-]gzip[;q=<non-zero>], or (b) there is a // *[;q=<non-zero>] and no [x-]gzip;q=0 to disable it. boolean identityEnabled = !zeros.contains("identity") && (!zeros.contains("*") || nonZeros.contains("identity")); boolean bzipEnabled = nonZeros.contains("bzip") || (nonZeros.contains("*") && !zeros.contains("bzip")); if (identityEnabled && !bzipEnabled) { permitted = UseBzip.NO; } else if (identityEnabled && bzipEnabled) { permitted = UseBzip.YES; message.put(BZIP_ENCODING_KEY, "bzip"); } else if (!identityEnabled && bzipEnabled) { permitted = UseBzip.FORCE; message.put(BZIP_ENCODING_KEY, "bzip"); } else { throw new Fault(new org.apache.cxf.common.i18n.Message("NO_SUPPORTED_ENCODING", BUNDLE)); } } else { LOG.fine("No accept-encoding header"); } } } if (LOG.isLoggable(Level.FINE)) { LOG.fine("bzip permitted: " + permitted); } return permitted; } static class BZipThresholdOutputStream extends AbstractThresholdOutputStream { Message message; public BZipThresholdOutputStream(int t, OutputStream orig, boolean force, Message msg) { super(t); super.wrappedStream = orig; message = msg; if (force) { setupBZip(); } } private void setupBZip() { } @Override public void thresholdNotReached() { //nothing LOG.fine("Message is smaller than compression threshold, not compressing."); } @Override public void thresholdReached() throws IOException { LOG.fine("Compressing message."); // Set the Content-Encoding HTTP header String enc = (String)message.get(BZIP_ENCODING_KEY); addHeader(message, "Content-Encoding", enc); // if this is a response message, add the Vary header if (!Boolean.TRUE.equals(message.get(Message.REQUESTOR_ROLE))) { addHeader(message, "Vary", "Accept-Encoding"); } // bzip the result CBZip2OutputStream bZip2Output = new CBZip2OutputStream(wrappedStream); wrappedStream = bZip2Output; } } /** * Adds a value to a header. If the given header name is not currently * set in the message, an entry is created with the given single value. * If the header is already set, the value is appended to the first * element of the list, following a comma. * * @param message the message * @param name the header to set * @param value the value to add */ private static void addHeader(Message message, String name, String value) { Map<String, List<String>> protocolHeaders = CastUtils.cast((Map<?, ?>)message .get(Message.PROTOCOL_HEADERS)); if (protocolHeaders == null) { protocolHeaders = new TreeMap<String, List<String>>(String.CASE_INSENSITIVE_ORDER); message.put(Message.PROTOCOL_HEADERS, protocolHeaders); } List<String> header = CastUtils.cast((List<?>)protocolHeaders.get(name)); if (header == null) { header = new ArrayList<String>(); protocolHeaders.put(name, header); } if (header.size() == 0) { header.add(value); } else { header.set(0, header.get(0) + "," + value); } } public void setForce(boolean force) { this.force = force; } }
配置文件:
<jaxrs:server id="" address="/"> <jaxrs:outInterceptors> <bean class="BZIPOutInterceptor"></bean> </jaxrs:outInterceptors> <jaxrs:serviceBeans> <ref bean="" /> </jaxrs:serviceBeans> <jaxrs:extensionMappings> <entry key="xml" value="application/xml" /> </jaxrs:extensionMappings> <jaxrs:languageMappings> <entry key="en" value="en-gb" /> </jaxrs:languageMappings> </jaxrs:server>
这样便能够实现如果请求头里Accept-Encoding 包含bzip压缩,服务器就自动进行bzip2压缩了。