什么是GZIP JSF-Seam Web应用程序页面的最佳方法

时间:2022-05-21 16:32:03

I'm developing an JSF web app on Tomcat, planning to use Seam in the near future, and I want to add compression of our web pages and resources (i.e. Javascript & CSS files). I'm aware of three methods to GZIP responses in a Java web :

我正在Tomcat上开发一个JSF Web应用程序,计划在不久的将来使用Seam,我想添加我们的网页和资源(即Javascript和CSS文件)的压缩。我知道Java Web中GZIP响应的三种方法:

  1. Use Ehcache GZIP filter: it's used in Appfuse, so it's probably solid and it checks if the user agent supports GZIP before applying it, but it seems to have problems with Seam, which we will be using http://seamframework.org/Community/EHCacheGZipFilterIncompatibleWithSeam.

    使用Ehcache GZIP过滤器:它在Appfuse中使用,所以它可能是可靠的,它会在应用之前检查用户代理是否支持GZIP,但它似乎与Seam有问题,我们将使用http://seamframework.org/Community / EHCacheGZipFilterIncompatibleWithSeam。

  2. Use pjl-filter. From the * question: Tomcat Compression Does Not Add a Content-Encoding: gzip in the Header, it appears it doesn't have any memory leaks, but I don't know if it has problems with Seam or not.

    使用pjl-filter。从*问题:Tomcat压缩不添加内容编码:在标头中的gzip,它似乎没有任何内存泄漏,但我不知道它是否有Seam问题。

  3. Use Tomcat's built in compression - although it may not provide a content encoding (Tomcat 6.0.14 seems to work fine, but you can only provide a black list for what user agents compression should not be applied to.

    使用Tomcat的内置压缩 - 虽然它可能不提供内容编码(Tomcat 6.0.14似乎工作正常,但您只能提供一个黑名单,用于不应用的用户代理压缩。

Does anyone have experience with these methods in a JSF-Seam environment? Which is the "best" solution?

有没有人在JSF-Seam环境中有这些方法的经验?哪个是“最佳”解决方案?

Thanks, Glen

8 个解决方案

#1


GZIP filter will reduce the initial load time significantly.
You can additionally implement a cacheFilter to bring performance of your screens at par with JavaScript based UI (https://*.com/a/35567540/5076414).
For client side components, you can use Primefaces which is JQuery based UI.

GZIP过滤器将显着减少初始加载时间。您还可以实现cacheFilter,以使您的屏幕性能与基于JavaScript的UI(https://*.com/a/35567540/5076414)相同。对于客户端组件,您可以使用基于JQuery的UI的Primefaces。

Enable GZIP filter in JSF

Simply add this to your

只需将此添加到您的

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>   

And the following to your

以下是你的

pom.xml

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

How to verify if my screen is using gzip

To see if your contents are already usign gzip and cache, In your Google Chrome Browser -> right click on your screen -> inspect -> click network tab -> refresh your screen. Click on the images, icons, stylesheets and see if you see following in response header

要查看您的内容是否已经使用gzip和缓存,请在您的Google Chrome浏览器中 - >右键单击您的屏幕 - >检查 - >单击网络选项卡 - >刷新屏幕。单击图像,图标,样式表,看看您是否在响应标题中看到以下内容

Content-Encoding:gzip if the status of element is 200

Content-Encoding:如果element的状态是200,则gzip

#2


How about adding an nginx front-end and letting it to do the compression (and caching)?

如何添加nginx前端并让它进行压缩(和缓存)?

http://wiki.nginx.org/Main

In this case, belongs on serverfalut :)

在这种情况下,属于serverfalut :)

#3


You should try the Jawr API

你应该尝试Jawr API

#4


We use JBoss Seam on JBoss AS proxied and load balanced behind apache + mod_proxy_ajp with mod_deflate to compress outgoing traffic.

我们在JBoss AS代理上使用JBoss Seam,并使用mod_deflate在apache + mod_proxy_ajp后面加载平衡以压缩传出流量。

Advantages of this setup

  • lots of examples in the net
  • 网上有很多例子

  • easy configuration/debugging considering quirks of different user agents
  • 考虑到不同用户代理的怪癖,易于配置/调试

  • changing the configuration at runtime (apachectl graceful instead of restarting webapp/tomcat to reflect changes).
  • 在运行时更改配置(apachectl graceful而不是重新启动webapp / tomcat以反映更改)。

#5


Use Tomcat's built in compression - although it may not provide a content encoding (Tomcat 6.0.14 seems to work fine, but you can only provide a black list for what user agents compression should not be applied to.

使用Tomcat的内置压缩 - 虽然它可能不提供内容编码(Tomcat 6.0.14似乎工作正常,但您只能提供一个黑名单,用于不应用的用户代理压缩。

I think that you misinterpreted the problem which you found in Tomcat Compression Does Not Add a Content-Encoding: gzip in the Header. That problem is caused by using Apache HTTPD with mod_jk in front of Tomcat which is in turn badly configured that it does not send the Content-Encoding header back from Tomcat. This problem is not caused by Tomcat itself. Tomcat is doing its job perfectly fine.

我认为你误解了你在Tomcat压缩中发现的问题不会添加内容编码:在标题中的gzip。这个问题是由于在Tomcat前面使用带有mod_jk的Apache HTTPD引起的,而后者又被错误地配置为不从Tomcat发回Content-Encoding头。此问题不是由Tomcat本身引起的。 Tomcat完美地完成了它的工作。

I'd say, just go ahead with Tomcat's builtin compression. It's as easy as adding compression="on" attribute to the HTTP connector in server.xml. You have next to the noCompressionUserAgents setting also the compressableMimeType setting. Read the HTTP Connector Documentation.

我会说,继续使用Tomcat的内置压缩。它就像在server.xml中的HTTP连接器中添加compression =“on”属性一样简单。您还可以在noCompressionUserAgents设置旁边使用compressableMimeType设置。阅读HTTP连接器文档。

#6


I tried a Servlet filter to add GZIP compression (not Ehcache though) and couldn't get it work properly. I ended up putting Apache with mod_jk in front of the app Server. All it took was a few minutes to configure GIP compressiion and I'm also feeling a lot more secure since just one app is exposed instead of the whole App Server.

我尝试了一个Servlet过滤器来添加GZIP压缩(虽然不是Ehcache)并且无法使其正常工作。我最终将Apache与mod_jk放在应用服务器的前面。所有这些只需要几分钟来配置GIP压缩,我也感觉更安全,因为只有一个应用程序被暴露而不是整个App Server。

#7


An alternative Servlet filter can be found here:

另一种Servlet过滤器可以在这里找到:

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

Like Ehcache, it tests to see if the browser supports it. I can't say categorically if it plays nicely with Seam, but I've used it in the past without trouble.

像Ehcache一样,它会测试浏览器是否支持它。我不能断断续续地说它是否和Seam一起玩得很好,但过去我没有遇到麻烦。

#8


I'm happy with the EhCache filter after some hacking. Here is how it works:

在经过一些黑客攻击后,我对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");
    }


}

#1


GZIP filter will reduce the initial load time significantly.
You can additionally implement a cacheFilter to bring performance of your screens at par with JavaScript based UI (https://*.com/a/35567540/5076414).
For client side components, you can use Primefaces which is JQuery based UI.

GZIP过滤器将显着减少初始加载时间。您还可以实现cacheFilter,以使您的屏幕性能与基于JavaScript的UI(https://*.com/a/35567540/5076414)相同。对于客户端组件,您可以使用基于JQuery的UI的Primefaces。

Enable GZIP filter in JSF

Simply add this to your

只需将此添加到您的

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>   

And the following to your

以下是你的

pom.xml

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

How to verify if my screen is using gzip

To see if your contents are already usign gzip and cache, In your Google Chrome Browser -> right click on your screen -> inspect -> click network tab -> refresh your screen. Click on the images, icons, stylesheets and see if you see following in response header

要查看您的内容是否已经使用gzip和缓存,请在您的Google Chrome浏览器中 - >右键单击您的屏幕 - >检查 - >单击网络选项卡 - >刷新屏幕。单击图像,图标,样式表,看看您是否在响应标题中看到以下内容

Content-Encoding:gzip if the status of element is 200

Content-Encoding:如果element的状态是200,则gzip

#2


How about adding an nginx front-end and letting it to do the compression (and caching)?

如何添加nginx前端并让它进行压缩(和缓存)?

http://wiki.nginx.org/Main

In this case, belongs on serverfalut :)

在这种情况下,属于serverfalut :)

#3


You should try the Jawr API

你应该尝试Jawr API

#4


We use JBoss Seam on JBoss AS proxied and load balanced behind apache + mod_proxy_ajp with mod_deflate to compress outgoing traffic.

我们在JBoss AS代理上使用JBoss Seam,并使用mod_deflate在apache + mod_proxy_ajp后面加载平衡以压缩传出流量。

Advantages of this setup

  • lots of examples in the net
  • 网上有很多例子

  • easy configuration/debugging considering quirks of different user agents
  • 考虑到不同用户代理的怪癖,易于配置/调试

  • changing the configuration at runtime (apachectl graceful instead of restarting webapp/tomcat to reflect changes).
  • 在运行时更改配置(apachectl graceful而不是重新启动webapp / tomcat以反映更改)。

#5


Use Tomcat's built in compression - although it may not provide a content encoding (Tomcat 6.0.14 seems to work fine, but you can only provide a black list for what user agents compression should not be applied to.

使用Tomcat的内置压缩 - 虽然它可能不提供内容编码(Tomcat 6.0.14似乎工作正常,但您只能提供一个黑名单,用于不应用的用户代理压缩。

I think that you misinterpreted the problem which you found in Tomcat Compression Does Not Add a Content-Encoding: gzip in the Header. That problem is caused by using Apache HTTPD with mod_jk in front of Tomcat which is in turn badly configured that it does not send the Content-Encoding header back from Tomcat. This problem is not caused by Tomcat itself. Tomcat is doing its job perfectly fine.

我认为你误解了你在Tomcat压缩中发现的问题不会添加内容编码:在标题中的gzip。这个问题是由于在Tomcat前面使用带有mod_jk的Apache HTTPD引起的,而后者又被错误地配置为不从Tomcat发回Content-Encoding头。此问题不是由Tomcat本身引起的。 Tomcat完美地完成了它的工作。

I'd say, just go ahead with Tomcat's builtin compression. It's as easy as adding compression="on" attribute to the HTTP connector in server.xml. You have next to the noCompressionUserAgents setting also the compressableMimeType setting. Read the HTTP Connector Documentation.

我会说,继续使用Tomcat的内置压缩。它就像在server.xml中的HTTP连接器中添加compression =“on”属性一样简单。您还可以在noCompressionUserAgents设置旁边使用compressableMimeType设置。阅读HTTP连接器文档。

#6


I tried a Servlet filter to add GZIP compression (not Ehcache though) and couldn't get it work properly. I ended up putting Apache with mod_jk in front of the app Server. All it took was a few minutes to configure GIP compressiion and I'm also feeling a lot more secure since just one app is exposed instead of the whole App Server.

我尝试了一个Servlet过滤器来添加GZIP压缩(虽然不是Ehcache)并且无法使其正常工作。我最终将Apache与mod_jk放在应用服务器的前面。所有这些只需要几分钟来配置GIP压缩,我也感觉更安全,因为只有一个应用程序被暴露而不是整个App Server。

#7


An alternative Servlet filter can be found here:

另一种Servlet过滤器可以在这里找到:

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

Like Ehcache, it tests to see if the browser supports it. I can't say categorically if it plays nicely with Seam, but I've used it in the past without trouble.

像Ehcache一样,它会测试浏览器是否支持它。我不能断断续续地说它是否和Seam一起玩得很好,但过去我没有遇到麻烦。

#8


I'm happy with the EhCache filter after some hacking. Here is how it works:

在经过一些黑客攻击后,我对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");
    }


}