3

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

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

  2. 使用 pjl 过滤器。从stackoverflow问题:Tomcat Compression Does Not Add a Content-Encoding: gzip in the Header,看来它没有任何内存泄漏,但我不知道Seam是否有问题。

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

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

谢谢,格伦

4

8 回答 8

5

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

在 JSF 中启用 GZIP 过滤器

只需将此添加到您的

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

于 2016-02-23T01:44:20.743 回答
1

我们JBoss SeamJBoss AS代理和负载平衡后面使用apache+ mod_proxy_ajpwithmod_deflate来压缩传出流量。

此设置的优点

  • 网上很多例子
  • 考虑到不同用户代理的怪癖,易于配置/调试
  • 在运行时更改配置(apachectl graceful而不是重新启动 webapp/tomcat 以反映更改)。
于 2011-07-28T10:07:06.210 回答
1

你应该试试 Jawr API

于 2009-10-15T14:55:00.093 回答
1

添加一个nginx前端并让它进行压缩(和缓存)怎么样?

http://wiki.nginx.org/Main

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

于 2009-06-10T20:26:21.967 回答
1

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

我认为您误解了在Tomcat Compression Does Not Add a Content-Encoding: gzip in the Header 中发现的问题。该问题是由在 Tomcat 前面使用带有 mod_jk 的 Apache HTTPD 引起的,而后者又被错误地配置为它不会Content-Encoding从 Tomcat 发回标头。这个问题不是Tomcat本身造成的。Tomcat 的工作做得非常好。

我会说,继续使用 Tomcat 的内置压缩。就像compression="on"server.xml. 您在设置旁边noCompressionUserAgents还有compressableMimeType设置。阅读HTTP 连接器文档

于 2011-07-28T12:33:29.083 回答
0

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

于 2009-09-23T01:12:35.583 回答
0

可以在这里找到一个替代的 Servlet 过滤器:

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

和 Ehcache 一样,它会测试浏览器是否支持它。我不能断然地说它是否能很好地与 Seam 配合使用,但我过去曾使用过它而没有遇到任何问题。

于 2009-11-03T15:44:48.900 回答
0

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


}
于 2011-07-28T12:49:05.583 回答