前端性能调优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设备的限制,有时搞好性能是一件难事.开发过程中你会有很多需要注意的 ...
随机推荐
- 集训第六周 古典概型 期望 C题
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=30728 一个立体方块,每个单位方块都是关闭状态,每次任两个点,以这两点为对角 ...
- jQuery中四个绑定事件的区别 on,bind,live,delegate
1.jQ操作DOM元素的绑定事件的四种方式 jQ中提供了四种事件监听方式,bind.live.delegate.on,对应的解除监听的函数分别是unbind,die,undelegate, ...
- codeforces 362B
#include<stdio.h> #include<stdlib.h> int cmp(const void *a,const void *b) { return *(int ...
- 洛谷P1186 玛丽卡
题目描述 麦克找了个新女朋友,玛丽卡对他非常恼火并伺机报复. 因为她和他们不住在同一个城市,因此她开始准备她的长途旅行. 在这个国家中每两个城市之间最多只有一条路相通,并且我们知道从一个城市到另一个城 ...
- vagrant的学习 之 LNMP和LAMP
vagrant的学习 之 LNMP和LAMP 本文根据慕课网的视频教程练习,感谢慕课网! 慕课的参考文档地址:https://github.com/apanly/mooc/tree/master/va ...
- Evaluate Reverse Polish Notation(逆波兰式)
Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are +, -, ...
- MongoDB小结07 - update【$pop】
如果将数组看做队列,可以用$pop方法删除第一个或者最后一个元素 {$pop:{"key":-1}},{$pop:{"key":1}}
- MongoDB小结01 - MongoDB简介
我们为什么要去学习MongoDB MongoDB是一种强大.灵活.可扩展的数据存储方式. 丰富的数据模型 MongoDB是面向文档的数据库,不是关系型数据库.它将原来'行'(row)的概念换成了更加灵 ...
- linux 硬件中断调节
什么是中断 中断interrupts是指硬件主动的来告诉CPU去做某些事情.比如网卡收到数据后可能主动的告诉CPU来处理自己接受到的数据,键盘有了按键输入后会主动告知CPU来读取输入. 硬件主动的打扰 ...
- 手动安装Firefox Linux
(2015-06-05 17:22:19)[编辑][删除] 转载▼ 标签: 股票 Firefox 下载文件以.tar和.bz2格式保存,必须从这些压缩包中提取文件.不想删除当前安装的 Firefox, ...