http応答内容の圧縮に関する小さな蓄積.
35412 ワード
1、tomcatのserver.xmlプロファイルに背景色を緑色にした設定を追加すると、サーバが自動的に圧縮されます.
詳細は以下の通りです.
BZIPPOut Interceptorコードは以下の通りです.
<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、bzip 2圧縮をサポートしたいなら、私の環境はapache cfxフレームで、GZIPPOut Interceptorと似たようなスクリーンショットをカスタマイズして、インタフェースのリリース配置ファイルに配置します.詳細は以下の通りです.
BZIPPOut Interceptorコードは以下の通りです.
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>
これにより、頭の中にあるAcceept Encocdingにbzip圧縮を含めるとサーバが自動的にbzep 2圧縮を行うことができます.