前端性能调优Gzip Filter
转自:https://blog.csdn.net/zxk15982106569/article/details/18922613
客户端向web服务器端发出了请求后,通常情况下服务器端会将页面文件和其他资源,返回到客户端,客户端加载后渲染呈现,这种情况文件一般都比较大,如果开启Gzip ,那么服务器端响应后,会将页面,JS,CSS等文本文件或者其他文件通过高压缩算法将其压缩,然后传输到客户端,由客户端的浏览器负责解压缩与呈现。通常能节省40%以上的流量(一般都有60%左右)。
现在主流浏览器都是支持gzip的。服务器压缩网页后进行传输,可减少传输数据的大小使用户感觉访问速度更快。当然,压缩也会消耗一部分服务器处理时间。
Web服务器处理HTTP压缩的过程如下:
1. Web服务器接收到浏览器的HTTP请求后,检查浏览器是否支持HTTP压缩(Accept-Encoding 信息);
2. 如果浏览器支持HTTP压缩,Web服务器检查请求文件的后缀名;
3. 如果请求文件是HTML、CSS等静态文件,Web服务器到压缩缓冲目录中检查是否已经存在请求文件的最新压缩文件;
4. 如果请求文件的压缩文件不存在,Web服务器向浏览器返回未压缩的请求文件,并在压缩缓冲目录中存放请求文件的压缩文件;
5. 如果请求文件的最新压缩文件已经存在,则直接返回请求文件的压缩文件;
6. 如果请求文件是动态文件,Web服务器动态压缩内容并返回浏览器,压缩内容不存放到压缩缓存目录中。
下面是两个演示图:
未使用Gzip:
开启使用Gzip后:
为了进行比较,我们先给个截图,这是没有启用Gzip的情况:
从这里可以看出,在启用Gzip之前,下载ext-all-debug.js需要2.8MB这么大的文件,需要用时1.53秒。
配置Gzip Filter后:
我们打开Firebug进行再次测试,作为结果的比较,果然性能提升很大:
从这我们不难看出,现在的Resource Header中 Content-Encoding被设置成了gzip,所以这表示我们的gzip的功能已经被正确的开启,然后我们发现ext-all-debug.js的尺寸从2.8MB缩小成了只有550KB,而且网络的传输时间从1.53秒缩短到了906毫秒,几乎减少了40%的下载时间,其他的资源也都相应的下载时间有了大幅度的减少。可见效果很明显。
应用(2种方式开启GZIP功能):
一.通过Tomcat 开启Gzip :
1.找到Tomcat 目录下的conf下的server.xml,并找到如下信息
将它改成如下的形式(其实在上面代码的下面已经有了,将他们打开而已。):
如图:
这样,就能够对html和xml进行压缩了,如果要压缩css 和 js,那么需要将
compressableMimeType=”text/html,text/xml”加入css和js:
你甚至可以压缩图片:
compressableMimeType=”text/html,text/xml”加入css和js:
开启后重启Tomcat ,通过浏览器查看headers信息就能看到是否开启(firebug中有),如果开启了,那么transfer-encoding就会是Gzip,否则就是chunked。
二.通过代码开启Gzip :
源码参看F:\odcdownload\IT资料\IT\GZIP filter\tk-filters-1.0.1.zip
解释:
.jsp进行gzip压缩可行方法
一、首先,去http://sourceforge.net/projects/filterlib网站下载tk-filters-1.0.1.zip。
二、解压这个tk-filters-1.0.1.zip压缩文件,将解压后的文件tk-filters.jar放在Ext项目的WEB-INF/lib/下。
三、打开解压后的文件夹tk-filters\conf\tk-filters.properties
GZIPFilter.Enabled=false(默认为false,true打开GZIP压缩功能)
GZIPFilter.LogStats=false(默认为false,true打开GZIP压缩功能日志,可以在后台看到压缩比例信息)
CacheFilter.Enabled=false(默认为false,true打开GZIP缓存功能)
注:可以自行选择想打开的功能,再将此文件复制到Ext项目的WEB-INF/class文件夹下(我这边eclipse3.5是WEB-INF/classes下面)
四、打开Ext项目的WEB-INF/web.xml文件
<!-- GZIPFilter压缩定义 设置此项时tk-filters.properties的GZIPFilter.Enabled=true才可用-->
<filter>
<filter-name>GZIPFilter</filter-name>
<filter-class>com.tacitknowledge.filters.gzipfilter.GZIPFilter</filter-class>
</filter>
<!-- GZIPFilter 设置自己想要压缩的文件类型-->
<filter-mapping>
<filter-name>GZIPFilter</filter-name>
<url-pattern>*.js</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>GZIPFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
<!-- CacheFilter缓存定义 设置此项时tk-filters.properties的CacheFilter.Enabled=true才可用 -->
<filter>
<filter-name>CacheFilter</filter-name>
<filter-class>com.tacitknowledge.filters.cache.CacheHeaderFilter</filter-class>
</filter>
<!-- CacheFilter 设置自己想要缓存的文件类型-->
<filter-mapping>
<filter-name>CacheFilter</filter-name>
<url-pattern>*.gif</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CacheFilter</filter-name>
<url-pattern>*.jpg</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CacheFilter</filter-name>
<url-pattern>*.png</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CacheFilter</filter-name>
<url-pattern>*.js</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CacheFilter</filter-name>
<url-pattern>*.css</url-pattern>
</filter-mapping>
五、测试:用的也是FireFox,以及FireBug调试测试。我的项目中用的Ext是3.2.1,ext-all.js为662KB。压缩后得到的大小仅为181K,压缩率达到了27%,页面加载速度得到了很大的提高。
以下是控制台打出来的压缩日志(GZIPFilter.LogStats=true会显示):
下面为大致的模仿以便理解:
(1).CachedResponseWrapper类
实现定制输出的关键是对HttpServletResponse 进行包装,截获所有的输出,等到过滤器链处理完毕后,再对截获的输出进行处理,并写入到真正的HttpServletResponse 对象中。JavaEE 框架已经定义了一个HttpServletResponseWrapper 类使得包装HttpServletResponse 更加容易。我们扩展这个HttpServletResponseWrapper,截获所有的输出,并保存到ByteArrayOutputStream 中。
定制的包装响应能方便地从帮助类 HttpServletResponseWrapper 中导出。这一类粗略地执行许多方法,允许我们简单地覆盖 getOutputStream() 方法以及 getWriter() 方法,提供了定制输出流的实例。
HttpServletResponseWrapper这个类的使用包括以下五个步骤:
1)建立一个响应包装器。扩展javax.servlet.http.HttpServletResponseWrapper。
2)提供一个缓存输出的PrintWriter。重载getWriter方法,返回一个保存发送给它的所有东西的PrintWriter,并把结果存进一个可以稍后访问的字段中。
3)传递该包装器给doFilter。此调用是合法的,因为HttpServletResponseWrapper实现HttpServletResponse。
4)提取和修改输出。在调用FilterChain的doFilter方法后,原资源的输出只要利用步骤2中提供的机制就可以得到。只要对你的应用适合,就可以修改或替换它。
5)发送修改过的输出到客户机。因为原资源不再发送输出到客户机(这些输出已经存放到你的响应包装器中了),所以必须发送这些输出。这样,你的过滤器需要从原响应对象中获得PrintWriter或OutputStream,并传递修改过的输出到该流中。
- /**
- * Wrapper:在内存中开辟一个ByteOutputStream,然后将拦截的响应写入byte[],
- * 写入完毕后,再将wrapper的byte[]写入真正的response对象
- * This class is used for wrapped response for getting cached data.
- */
- class CachedResponseWrapper extends HttpServletResponseWrapper {
- /**
- * Indicate that getOutputStream() or getWriter() is not called yet.
- */
- public static final int OUTPUT_NONE = 0;
- /**
- * Indicate that getWriter() is already called.
- */
- public static final int OUTPUT_WRITER = 1;
- /**
- * Indicate that getOutputStream() is already called.
- */
- public static final int OUTPUT_STREAM = 2;
- private int outputType = OUTPUT_NONE;
- private int status = SC_OK;
- private ServletOutputStream output = null;
- private PrintWriter writer = null;
- private ByteArrayOutputStream buffer = null;
- public CachedResponseWrapper(HttpServletResponse resp) throws IOException {
- super(resp);
- buffer = new ByteArrayOutputStream();
- }
- public int getStatus() {
- return status;
- }
- public void setStatus(int status) {
- super.setStatus(status);
- this.status = status;
- }
- public void setStatus(int status, String string) {
- super.setStatus(status, string);
- this.status = status;
- }
- public void sendError(int status, String string) throws IOException {
- super.sendError(status, string);
- this.status = status;
- }
- public void sendError(int status) throws IOException {
- super.sendError(status);
- this.status = status;
- }
- public void sendRedirect(String location) throws IOException {
- super.sendRedirect(location);
- this.status = SC_MOVED_TEMPORARILY;
- }
- public PrintWriter getWriter() throws IOException {
- if (outputType == OUTPUT_STREAM)
- throw new IllegalStateException();
- else if (outputType == OUTPUT_WRITER)
- return writer;
- else {
- outputType = OUTPUT_WRITER;
- writer = new PrintWriter(new OutputStreamWriter(buffer,
- getCharacterEncoding()));
- return writer;
- }
- }
- public ServletOutputStream getOutputStream() throws IOException {
- if (outputType == OUTPUT_WRITER)
- throw new IllegalStateException();
- else if (outputType == OUTPUT_STREAM)
- return output;
- else {
- outputType = OUTPUT_STREAM;
- output = new WrappedOutputStream(buffer);
- return output;
- }
- }
- public void flushBuffer() throws IOException {
- if (outputType == OUTPUT_WRITER)
- writer.flush();
- if (outputType == OUTPUT_STREAM)
- output.flush();
- }
- public void reset() {
- outputType = OUTPUT_NONE;
- buffer.reset();
- }
- /**
- * Call this method to get cached response data.
- *
- * @return byte array buffer.
- * @throws IOException
- */
- public byte[] getResponseData() throws IOException {
- flushBuffer();
- return buffer.toByteArray();
- }
- /**
- * This class is used to wrap a ServletOutputStream and store output stream
- * in byte[] buffer.
- */
- class WrappedOutputStream extends ServletOutputStream {
- private ByteArrayOutputStream buffer;
- public WrappedOutputStream(ByteArrayOutputStream buffer) {
- this.buffer = buffer;
- }
- public void write(int b) throws IOException {
- buffer.write(b);
- }
- public byte[] toByteArray() {
- return buffer.toByteArray();
- }
- }
- }
(2).GZipFilter类
- public class GZipFilter implements Filter {
- public void init(FilterConfig arg0) throws ServletException {
- }
- public void doFilter(ServletRequest request, ServletResponse response,
- FilterChain chain) throws IOException, ServletException {
- HttpServletResponse httpResponse = (HttpServletResponse) response;
- CachedResponseWrapper wrapper = new CachedResponseWrapper(httpResponse);
- // 写入wrapper:
- chain.doFilter(request, wrapper);
- // 对响应进行处理,这里是进行GZip压缩:
- byte[] data = GZipUtil.gzip(wrapper.getResponseData());
- httpResponse.setHeader("Content-Encoding", "gzip");
- httpResponse.setContentLength(data.length);
- ServletOutputStream output = response.getOutputStream();
- output.write(data);
- output.flush();
- }
- public void destroy() {
- }
- }
(3).GZipUtil类
- public final class GZipUtil {
- /** * Do a gzip operation. */
- public static byte[] gzip(byte[] data) {
- ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(10240);
- GZIPOutputStream output = null;
- try {
- output = new GZIPOutputStream(byteOutput);
- output.write(data);
- } catch (IOException e) {
- throw new RuntimeException("G-Zip failed.", e);
- } finally {
- if (output != null) {
- try {
- output.close();
- } catch (IOException e) {
- }
- }
- }
- return byteOutput.toByteArray();
- }
- }
(4).在web.xml中配置 GZipFilter
- <filter>
- <filter-name>GZipFilter</filter-name>
- <filter-class>com.logcd.filter.GZipFilter</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>GZipFilter</filter-name>
- <url-pattern>*.html</url-pattern>
- </filter-mapping>
前端性能调优Gzip Filter的更多相关文章
- web前端性能调优(二)
项目经过第一波优化之后APP端已基本已经符合我们的要求了,但是TV端还是反应比较慢,页面加载和渲染都比较慢了一点,我觉的还是有必要在进行一些优化,经过前面的优化,我们的优化空间已经小了一部分,不过还是 ...
- web前端性能调优
最近2个月一直在做手机端和电视端开发,开发的过程遇到过各种坑.弄到快元旦了,终于把上线了.2个月干下来满满的的辛苦,没有那么忙了自己准备把前端的性能调优总结以下,以方便以后自己再次使用到的时候得于得心 ...
- web前端性能调优(一)
最近2个月一直在做手机端和电视端开发,开发的过程遇到过各种坑.弄到快元旦了,终于把上线了.2个月干下来满满的的辛苦,没有那么忙了自己准备把前端的性能调优总结以下,以方便以后自己再次使用到的时候得于得心 ...
- [网站性能2]Asp.net平台下网站性能调优的实战方案
文章来源:http://www.cnblogs.com/dingjie08/archive/2009/11/10/1599929.html 前言 最近帮朋友运营的平台进行了性能调优,效果还不错, ...
- Asp.net平台下网站性能调优的实战方案(转)
转载地址:http://www.cnblogs.com/chenkai/archive/2009/11/07/1597795.html 前言 最近帮朋友运营的平台进行了性能调优,效果还不错,所以写出来 ...
- solr研磨之性能调优
作者:战斗民族就是干 转载请注明地址:http://www.cnblogs.com/prayers/p/8982141.html 本篇文章我们来了解一下solr的性能方面的调优,分为Schema优化 ...
- 性能测试day03_前端分析调优思路
刚刚看到有人支持我写的博客,表示还是比较感动的,发现热心的用户在我的博客留言说“一个系统每天有200万在线用户,问我怎么设计性能场景?”,其实这个问题呢就属于业务没理清,这个问题就像我问你,一个城市一 ...
- Nginx 性能调优
原文地址:http://nginx.com/blog/tuning-nginx/ Tuning NGINX for Performance Nginx 性能调优 NGINX is well known ...
- iOS-------应用性能调优的25个建议和技巧
性能对 iOS 应用的开发尤其重要,如果你的应用失去反应或者很慢,失望的用户会把他们的失望写满App Store的评论.然而由于iOS设备的限制,有时搞好性能是一件难事.开发过程中你会有很多需要注意的 ...
随机推荐
- LINUX系统---初级相关操作和知识
LINUX系统的初级,从安装LINUX开始,到处理简单的运维问题.搭建各种服务.解决网路问题.缓解服务器压力,写简单的shell脚本. 我们从基本的入门开始搞事情: 安装LINUX系统 对磁盘的使用 ...
- rbac组件之权限初始化(五)
当用户登陆后,根据用户的角色要为用户生成对应的权限菜单,此时需要将登陆的用户信息获取且获取角色信息,从数据库中获取菜单以及权限信息,并且存入session中. 1.权限流程 第一次请求的页面是登陆页面 ...
- 理解ZAB协议
ZAB协议 介绍 1.zab协议是为分布式协调服务zookpeer专门设计的一种支持崩溃恢复的原子广播协议 2.在zookeeper中主要依赖ZAB协议来实现数据一致性,基于该协议zk实现了一种主备模 ...
- Python随笔day01
环境变量的配置: 配置Python的安装目录到path变量中,例如C:\Python37 标识符的命名规则: 变量名只能以数字,字母,下划线组成. 不能以数字开头,保留字不能被使用. 建议使用下划线分 ...
- 杭电 5053 the Sum of Cube(求区间内的立方和)打表法
Description A range is given, the begin and the end are both integers. You should sum the cube of al ...
- jQuery调用WCF 说明
在项目中用过一些WCF的技术这篇文章是对以前用过的一点东西的一个梳理 一,webconfig的配置除了一般的配置外,与WCF相关的配置如下 <system.serviceModel> ...
- Open DBDiff 0.9
SQL Server 迁移过程经常会的出现,需要比对两个数据库之间,或者是表之间到底有何不同 SQL server 自带的tablediff Utility 是一个命令行的工具,对于偶尔需要做一次的体 ...
- Jmeter关联,正则表达式提取器使用2
正则表达式的用处很多,最基础的用法 1,断言 2,传参(关联) 例子 1.http请求 2正则表达式提取,想要提取列表列中id,一遍打开列表页 如果是1,每次就会取相同的值!匹配数字的权限高于模板$0 ...
- Leetcode 220.存在重复元素III
存在重复元素III 给定一个整数数组,判断数组中是否有两个不同的索引 i 和 j,使得 nums [i] 和 nums [j] 的差的绝对值最大为 t,并且 i 和 j 之间的差的绝对值最大为 ķ. ...
- baidu 和 es 使用
http://www.cnblogs.com/kangoroo/p/8047586.html