Какой тип сжатия сервлетов (GZIP самый популярный) вы бы предложили?
Я ищу сервлет-фильтр GZIP для использования в веб-приложении большого объема. Я не хочу использовать определенные параметры контейнера.
требование
- Возможность сжимать полезную нагрузку ответа (XML)
- Быстрее
- Проверено в производстве для больших объемов
- Должен правильно установить соответствующее Content-Encoding
- портативный через контейнеры
- Опционально может распаковать запрос
Спасибо.
5 ответов
Из того, что я видел, большинство людей обычно используют фильтр сжатия gzip. Как правило, из ehcache.
Реализация фильтра GZIP: net.sf.ehcache.constructs.web.filter.GzipFilter
Координата Maven для включения его в ваш проект:
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-web</artifactId>
<version>2.0.4</version>
</dependency>
Вам также нужно будет указать цель ведения журнала SLF4J. Если вы не знаете, что это такое, или вам все равно, slf4j-jdk14 или slf4j-simple works:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.6.4</version>
</dependency>
Фильтр GZIP, который я использую для сжатия ресурсов в моих веб-приложениях:
public class CompressionFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String acceptEncoding = httpRequest.getHeader(HttpHeaders.ACCEPT_ENCODING);
if (acceptEncoding != null) {
if (acceptEncoding.indexOf("gzip") >= 0) {
GZIPHttpServletResponseWrapper gzipResponse = new GZIPHttpServletResponseWrapper(httpResponse);
chain.doFilter(request, gzipResponse);
gzipResponse.finish();
return;
}
}
chain.doFilter(request, response);
}
public void init(FilterConfig filterConfig) throws ServletException {
}
}
public class GZIPHttpServletResponseWrapper extends HttpServletResponseWrapper {
private ServletResponseGZIPOutputStream gzipStream;
private ServletOutputStream outputStream;
private PrintWriter printWriter;
public GZIPHttpServletResponseWrapper(HttpServletResponse response) throws IOException {
super(response);
response.addHeader(HttpHeaders.CONTENT_ENCODING, "gzip");
}
public void finish() throws IOException {
if (printWriter != null) {
printWriter.close();
}
if (outputStream != null) {
outputStream.close();
}
if (gzipStream != null) {
gzipStream.close();
}
}
@Override
public void flushBuffer() throws IOException {
if (printWriter != null) {
printWriter.flush();
}
if (outputStream != null) {
outputStream.flush();
}
super.flushBuffer();
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
if (printWriter != null) {
throw new IllegalStateException("printWriter already defined");
}
if (outputStream == null) {
initGzip();
outputStream = gzipStream;
}
return outputStream;
}
@Override
public PrintWriter getWriter() throws IOException {
if (outputStream != null) {
throw new IllegalStateException("printWriter already defined");
}
if (printWriter == null) {
initGzip();
printWriter = new PrintWriter(new OutputStreamWriter(gzipStream, getResponse().getCharacterEncoding()));
}
return printWriter;
}
@Override
public void setContentLength(int len) {
}
private void initGzip() throws IOException {
gzipStream = new ServletResponseGZIPOutputStream(getResponse().getOutputStream());
}
}
public class ServletResponseGZIPOutputStream extends ServletOutputStream {
GZIPOutputStream gzipStream;
final AtomicBoolean open = new AtomicBoolean(true);
OutputStream output;
public ServletResponseGZIPOutputStream(OutputStream output) throws IOException {
this.output = output;
gzipStream = new GZIPOutputStream(output);
}
@Override
public void close() throws IOException {
if (open.compareAndSet(true, false)) {
gzipStream.close();
}
}
@Override
public void flush() throws IOException {
gzipStream.flush();
}
@Override
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
if (!open.get()) {
throw new IOException("Stream closed!");
}
gzipStream.write(b, off, len);
}
@Override
public void write(int b) throws IOException {
if (!open.get()) {
throw new IOException("Stream closed!");
}
gzipStream.write(b);
}
}
Вам также нужно определить отображение в вашем файле web.xml:
<filter>
<filter-name>CompressionFilter</filter-name>
<filter-class>com.my.company.CompressionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CompressionFilter</filter-name>
<url-pattern>*.js</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CompressionFilter</filter-name>
<url-pattern>*.css</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CompressionFilter</filter-name>
<url-pattern>*.html</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CompressionFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
Проверьте pjl-comp-фильтр CompressingFilter:
Я бы порекомендовал вам использовать что-то перед tomcat для разгрузки gzipping. Apache с mod_deflate будет работать хорошо. У вас есть возможность поместить apache в тот же ящик или перенести его в другой ящик, чтобы сжатие не влияло на ваше приложение. mod_jk или mod_proxy будут нормально работать в этой настройке.
Или, если вы используете Nginx, смотрите здесь: http://nginx.org/en/docs/http/ngx_http_gzip_module.html. Но определенно, как сказал Зеки, лучше перенести это на выделенный веб-сервер.