Каков наилучший метод для GZIP на страницах веб-приложений JSF-Seam

Я разрабатываю веб-приложение JSF на Tomcat, планирую использовать Seam в ближайшем будущем, и я хочу добавить сжатие наших веб-страниц и ресурсов (т.е. Javascript и файлы CSS). Я знаю три метода ответов GZIP в веб-среде Java:

  • Используйте фильтр Ehcache GZIP: он используется в Appfuse, поэтому он, вероятно, прочный и проверяет, поддерживает ли пользовательский агент GZIP перед его применением, но, похоже, у него проблемы с Seam, который мы будем использовать http://seamframework.org/Community/EHCacheGZipFilterIncompatibleWithSeam.

  • Используйте pjl-фильтр. Из вопроса stackoverflow: Компрессия Tomcat не добавляет кодировку содержимого: gzip в заголовке, похоже, что у нее нет утечек памяти, но я не знать, есть ли у него проблемы с швом или нет.

  • Используйте Tomcat, встроенный в сжатие, хотя он может не предоставлять кодировку содержимого (Tomcat 6.0.14, похоже, работает нормально, но вы можете предоставить только черный список, для которого нельзя применять сжатие пользовательских агентов.

Есть ли у кого-нибудь опыт работы с этими методами в среде JSF-Seam? Какое "лучшее" решение?

Спасибо, Glen

Ответы

Ответ 1

Фильтр GZIP значительно сократит время начальной загрузки.
Вы можете дополнительно реализовать cacheFilter, чтобы обеспечить производительность ваших экранов наравне с пользовательским интерфейсом на основе JavaScript (fooobar.com/questions/8784/...).
Для клиентских компонентов вы можете использовать Primefaces, который является пользовательским интерфейсом на основе JQuery.

Включить фильтр GZIP в JSF

Просто добавьте это в свой

web.xml

<filter>
    <filter-name>gzipResponseFilter</filter-name>
    <filter-class>org.omnifaces.filter.GzipResponseFilter</filter-class>
    <init-param>
        <description>The threshold size in bytes. Must be a number between 0 and 9999. Defaults to 150.</description>
        <param-name>threshold</param-name>
        <param-value>150</param-value>
    </init-param>
    <init-param>
        <description>The mimetypes which needs to be compressed. Must be a commaseparated string. Defaults to the below values.</description>
        <param-name>mimetypes</param-name>
        <param-value>
     text/plain, text/html, text/xml, text/css, text/javascript, text/csv, text/rtf,
     application/xml, application/xhtml+xml, application/x-javascript, application/javascript, application/json,
     image/svg+xml, image/gif, application/x-font-woff, application/font-woff2, image/png
 </param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>gzipResponseFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>
<error-page>
    <exception-type>java.lang.Throwable</exception-type>
    <location>/</location>
</error-page>   

И следующее к вашему

pom.xml

    <dependency>
        <groupId>org.omnifaces</groupId>
        <artifactId>omnifaces</artifactId>
        <version>1.11</version>
    </dependency>

Как проверить, использует ли мой экран gzip

Чтобы узнать, уже ли ваше содержимое уже используется в gzip и кеше, в браузере Google Chrome - щелкните правой кнопкой мыши на экране → проверьте → нажмите вкладку сети → обновите экран. Нажмите на изображения, значки, таблицы стилей и посмотрите, видите ли вы следующее в заголовке ответа

Content-Encoding:gzip, если статус элемента равен 200

Ответ 2

Как добавить добавочный интерфейс nginx и позволить ему выполнить сжатие (и кеширование)?

http://wiki.nginx.org/Main

В этом случае принадлежит serverfalut:)

Ответ 3

Вам следует попробовать API Jawr

Ответ 4

Мы используем JBoss Seam в JBoss AS прокси и балансировку нагрузки <<22 > + mod_proxy_ajp с помощью mod_deflate для сжатия исходящего трафика.

Преимущества этой настройки

  • множество примеров в сети
  • простая настройка/отладка с учетом особенностей различных пользовательских агентов
  • изменение конфигурации во время выполнения (apachectl graceful вместо перезапуска webapp/tomcat для отражения изменений).

Ответ 5

Используйте Tomcat, встроенный в сжатие, хотя он может и не предоставлять кодировку содержимого (Tomcat 6.0.14, похоже, работает нормально, но вы можете предоставить только черный список, для которого нельзя применять сжатие пользовательских агентов.

Я думаю, что вы неправильно истолковали проблему, которую вы нашли в Сжатие Tomcat не добавляет кодировку содержимого: gzip в заголовке. Эта проблема вызвана использованием Apache HTTPD с mod_jk перед Tomcat, который, в свою очередь, плохо настроен, что он не отправляет заголовок Content-Encoding обратно из Tomcat. Эта проблема не, вызванная самим Tomcat. Tomcat отлично справляется со своей задачей.

Я бы сказал, просто продолжайте компиляцию Tomcat. Это так же просто, как добавление атрибута compression="on" к HTTP-коннектору в server.xml. У вас рядом с настройкой noCompressionUserAgents также параметр compressableMimeType. Прочтите Документацию по HTTP-коннектору.

Ответ 6

Я попробовал фильтр Servlet, чтобы добавить сжатие GZIP (но не Ehcache) и не смог заставить его работать правильно. В итоге я поставил Apache с mod_jk перед сервером приложений. Все, что потребовалось, было несколько минут, чтобы настроить GIP compressiion, и я также чувствую себя намного более безопасным, поскольку только одно приложение открыто, а не весь сервер приложений.

Ответ 7

Альтернативный сервлет-фильтр можно найти здесь:

http://onjava.com/pub/a/onjava/2003/11/19/filters.html

Как и Ehcache, он проверяет, поддерживает ли браузер его. Я не могу сказать категорически, если он хорошо играет с Seam, но я использовал его в прошлом без проблем.

Ответ 8

Я доволен фильтром EhCache после некоторого взлома. Вот как это работает:

package myapp;

import net.sf.ehcache.constructs.web.GenericResponseWrapper;
import net.sf.ehcache.constructs.web.ResponseUtil;
import static org.jboss.seam.ScopeType.STATELESS;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.annotations.web.Filter;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.GZIPOutputStream;

/**
 * Zip content before sending to the browser.
 * 
 * 
 */
@Name("gzipFilter")
@Scope(STATELESS)
@BypassInterceptors
@Filter(around = "org.jboss.seam.web.ajax4jsfFilterInstantiator")
public class GzipFilter extends net.sf.ehcache.constructs.web.filter.Filter
{

    private static final Logger LOG = Logger.getLogger(GzipFilter.class.getName());

    /**
     * Performs initialisation.
     *
     * @param filterConfig config
     */
    protected void doInit(FilterConfig filterConfig) throws Exception
    {
        //nothing required.
    }


    /**
     * A template method that performs any Filter specific destruction tasks.
     * Called from {@link #destroy()}
     */
    protected void doDestroy()
    {
        //noop
    }

    /**
     * Performs the filtering for a request.
     */
    protected void doFilter(final HttpServletRequest request, final HttpServletResponse response,
                            final FilterChain chain) throws Exception
    {
        if (!isDocStore(request) && !isIncluded(request) && acceptsEncoding(request, "gzip"))
        {
            // Client accepts zipped content
            if (LOG.isLoggable(Level.FINE))
            {
                LOG.fine(request.getRequestURL() + ". Writing with gzip compression");
            }

            // Create a gzip stream
            final ByteArrayOutputStream compressed = new ByteArrayOutputStream();
            final GZIPOutputStream gzout = new GZIPOutputStream(compressed);

            // Handle the request
            final GenericResponseWrapper wrapper = new GenericResponseWrapper(response, gzout);
            chain.doFilter(request, wrapper);
            wrapper.flush();

            gzout.close();

            //return on error or redirect code, because response is already committed
            int statusCode = wrapper.getStatus();
            if (statusCode != HttpServletResponse.SC_OK)
            {
                return;
            }

            //Saneness checks
            byte[] compressedBytes = compressed.toByteArray();
            boolean shouldGzippedBodyBeZero = ResponseUtil.shouldGzippedBodyBeZero(compressedBytes, request);
            boolean shouldBodyBeZero = ResponseUtil.shouldBodyBeZero(request, wrapper.getStatus());
            if (shouldGzippedBodyBeZero || shouldBodyBeZero)
            {
                compressedBytes = new byte[0];
            }

            // Write the zipped body
            //ResponseUtil.addGzipHeader(response);
            response.setHeader("Content-Encoding", "gzip");
            response.setContentLength(compressedBytes.length);


            response.getOutputStream().write(compressedBytes);
        } else
        {
            // Client does not accept zipped content - don't bother zipping
            if (LOG.isLoggable(Level.FINE))
            {
                LOG.fine(request.getRequestURL()
                        + ". Writing without gzip compression because the request does not accept gzip.");
            }
            chain.doFilter(request, response);
        }
    }


    /**
     * Checks if the request uri is an include.
     * These cannot be gzipped.
     *
     * @param request the request
     * @return true if included
     */
    private boolean isIncluded(final HttpServletRequest request)
    {
        final String uri = (String) request.getAttribute("javax.servlet.include.request_uri");
        final boolean includeRequest = !(uri == null);

        if (includeRequest && LOG.isLoggable(Level.FINE))
        {
            LOG.fine(request.getRequestURL() + " resulted in an include request. This is unusable, because" +
                    "the response will be assembled into the overrall response. Not gzipping.");
        }
        return includeRequest;
    }

    private boolean isDocStore(final HttpServletRequest request)
    {
        return request.getRequestURI().indexOf("/docstore/") > 0;
    }

    /**
     * Determine whether the user agent accepts GZIP encoding. This feature is part of HTTP1.1.
     * If a browser accepts GZIP encoding it will advertise this by including in its HTTP header:
     * <p/>
     * <code>
     * Accept-Encoding: gzip
     * </code>
     * <p/>
     * Requests which do not accept GZIP encoding fall into the following categories:
     * <ul>
     * <li>Old browsers, notably IE 5 on Macintosh.
     * <li>Internet Explorer through a proxy. By default HTTP1.1 is enabled but disabled when going
     * through a proxy. 90% of non gzip requests seen on the Internet are caused by this.
     * </ul>
     * As of September 2004, about 34% of Internet requests do not accept GZIP encoding.
     *
     * @param request the request
     * @return true, if the User Agent request accepts GZIP encoding
     */
    protected boolean acceptsGzipEncoding(HttpServletRequest request)
    {
        return acceptsEncoding(request, "gzip");
    }


}