使用gzip优化web应用(filter实现)

相关知识:

  gzip是http协议中使用的一种加密算法,客户端向web服务器端发出了请求后,通常情况下服务器端会将页面文件和其他资源,返回到客户端,客户端加载后渲染呈现,这种情况文件一般都比较大,如果开启Gzip ,那么服务器端响应后,会将页面,JS,CSS等文本文件或者其他文件通过高压缩算法将其压缩,然后传输到客户端,由客户端的浏览器负责解压缩与呈现。通常能节省40%以上的流量(一般都有60%左右),一些PHP,JSP文件也能够进行压缩。

 

1.实现:  

Tomcat 开启Gzip :

1.找到Tomcat 目录下的conf下的server.xml,并找到如下信息

Connector port="8080" maxHttpHeaderSize="8192" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" redirectPort="8443" acceptCount="100" connectionTimeout="20000" disableUploadTimeout="true"

将它改成如下的形式(其实在上面代码的下面已经有了,将他们打开而已。):

<!-- Define a non-SSL HTTP/1.1 Connector on port 8080 --> <Connector port="8080" maxHttpHeaderSize="8192" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" redirectPort="8443" acceptCount="100" connectionTimeout="20000" disableUploadTimeout="true" compression="on" compressionMinSize="2048" noCompressionUserAgents="gozilla, traviata" compressableMimeType="text/html,text/xml" >

这样,就能够对html和xml进行压缩了,如果要压缩css 和 js,那么需要将

compressableMimeType=”text/html,text/xml”加入css和js:

<Connector port="8080" ......... compressableMimeType="text/html,text/xml,text/css,text/javascript" >

你甚至可以压缩图片:

compressableMimeType=”text/html,text/xml”加入css和js:

<Connector port="8080" ......... compressableMimeType="text/html,text/xml,text/css,text/javascript,image/gif,image/jpg" >

开启后重启Tomcat ,通过浏览器查看headers信息就能看到是否开启(firebug中有),如果开启了,那么transfer-encoding就会是Gzip,否则就是chunked。

 

 

2.在代码级别完成web应用的gzip压缩的开启:

 

 

1.Wrapper  用来包装HttpServletResponse 对象

 

package com.shop.gzip;import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;public class Wrapper extends HttpServletResponseWrapper {public static final int OT_NONE = 0, OT_WRITER = 1, OT_STREAM = 2;private int outputType = OT_NONE;private ServletOutputStream output = null;private PrintWriter writer = null;private ByteArrayOutputStream buffer = null;public Wrapper(HttpServletResponse resp) throws IOException {super(resp);buffer = new ByteArrayOutputStream();}public PrintWriter getWriter() throws IOException {if (outputType == OT_STREAM)throw new IllegalStateException();else if (outputType == OT_WRITER)return writer;else {outputType = OT_WRITER;writer = new PrintWriter(new OutputStreamWriter(buffer,getCharacterEncoding()));return writer;}}public ServletOutputStream getOutputStream() throws IOException {if (outputType == OT_WRITER)throw new IllegalStateException();else if (outputType == OT_STREAM)return output;else {outputType = OT_STREAM;output = new WrappedOutputStream(buffer);return output;}}public void flushBuffer() throws IOException {if (outputType == OT_WRITER)writer.flush();if (outputType == OT_STREAM)output.flush();}public void reset() {outputType = OT_NONE;buffer.reset();}public byte[] getResponseData() throws IOException {flushBuffer();return buffer.toByteArray();}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.过滤器

package com.shop.gzip;import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class GZipFilter implements Filter {public void destroy() {}/*** 判断浏览器是否支持GZIP* @param request* @return*/private static boolean isGZipEncoding(HttpServletRequest request){boolean flag=false;String encoding=request.getHeader("Accept-Encoding");if(encoding.indexOf("gzip")!=-1){flag=true;}return flag;}public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {HttpServletResponse resp = (HttpServletResponse) response;HttpServletRequest req=(HttpServletRequest)request;if(isGZipEncoding(req)){Wrapper wrapper = new Wrapper(resp);chain.doFilter(request, wrapper);byte[] gzipData = gzip(wrapper.getResponseData());resp.addHeader("Content-Encoding", "gzip");resp.setContentLength(gzipData.length);ServletOutputStream output = response.getOutputStream();output.write(gzipData);output.flush();} else {chain.doFilter(request, response);}        }public void init(FilterConfig arg0) throws ServletException {}private byte[] gzip(byte[] data) {ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(10240);GZIPOutputStream output = null;try {output = new GZIPOutputStream(byteOutput);output.write(data);} catch (IOException e) {} finally {try {output.close();} catch (IOException e) {}}return byteOutput.toByteArray();}}

 

3.在web.xml中配置 GZipFilter,当我们访问应用中以.do结尾的资源的使用,服务器端就开启http gzip压缩,将压缩后的信息通过http 协议传递给浏览器.

<filter>  <filter-name>ecsideExport</filter-name>  <filter-class>com.web.servlet.GZipFilter</filter-class>  </filter>  <filter-mapping>  <filter-name>ecsideExport</filter-name>  <url-pattern>*.do</url-pattern>  </filter-mapping>  

 

 



番外:使用Jayson Falkner的过滤器

 

Jayson Falkner 在他的Two Servlet Filters Every Web Application Should Have(http://www.onjava.com/pub/a/onjava/2003/11/19/filters.html?page=1 ) 里面介绍了2个提高Java Web Application 效能的Servlet。这里记一下其中的GZIPFilter。
GZIPFilter可以用gzip的方式压缩HTTP Response的内容,从而在Server端加快了响应回复的速度(gzip压缩过程需耗用CPU资源,却大幅减轻了网卡的处理负担),在Client端缩短了页面刷新时间,在网络内减少了数据流量。另一方面,因为采用的Filter的方式,无需改动应用现有的代码就可引入该功能。

 


以上Filter的source code在这里(http://www.onjava.com/onjava/2003/11/19/examples/jspbook.zip )下载。当然也可以在这里(http://www.onjava.com/onjava/2003/11/19/examples/jspbook.jar )下载现成的JAR。

作者定义了3个类来实现这个压缩功能:GZIPFilter, GZIPResponseWrapper, GZIPResponseStream。类图大致如下:

 


这3个类要做的,就是在Server将响应内容装入HTTP Response之前,先对内容进行GZIP压缩。其中GZIPFilter实现了javax.servlet.Filter接口,在Java Web Container处理HTTP Response的过程中便可以挂载使用。另外2个类(GZIPResponseWrapper,GZIPResponseStream)基本上是辅助类,真正的压缩动作是在GZIPResponseStream中由java.util.zip.GZIPOutputStream来完成的,除此还有其它的一些方法,感觉似乎并没有全部用到。这部分还需要另外再研究。

 

要布署这个Filter也很简单。只要将JAR放至应用的library目录,并且在应用的布署配置文件web.xml中加入

GZIPFilter

com.jspbook.GZIPFilter

GZIPFilter

/*.jsp

然后启动Server就可以了。

GZIPFilter压缩HTTP Response内容的作用非常明显。作者在source code的包里面另外放了TestGZIP.jsp,这是用来显示GZIPFilter的压缩效果的JSP。你可以找一支产生大量内容的目标JSP来测验一下,就像下面这支show_response_compressed.jsp:

<%@ page import="java.io.*" %><%@ page import="java.util.zip.*" %><%String title = "Show Compressed Response";int size = 100000;out.println("<HTML>/n" +"<HEAD><TITLE>" + title + "</TITLE></HEAD>/n" +"<BODY BGCOLOR=/"#FDF5E6/">/n" +"<H1 ALIGN=/"CENTER/">" + title + " SIZE="+size+"</H1>/n");String line = "Blah, blah, blah, blah, blah. " +"Yadda, yadda, yadda, yadda.";for(int i=0; i<size; i++) {out.println(line);}out.println("</BODY></HTML>");%>

运行show_response_compressed.jsp可以产生类似如下截图中的页面。

 

 

 

运行TestGZIP.jsp,在URL中填入show_response_compressed.jsp 所在的地址,提交后即可得到如下结果。

 


 

可以看到,未经压缩的HTTP Response数据量达到了2,950,086 bytes (2.9MB),而压缩后的数据量仅有8,687 bytes(8 KB),压缩比高达99.7%!

 


因为是在一台机器上作的验证,所以在响应时间的改善方面感觉不是很明显。同样的,如果是在Intranet环境内,则这种效果也不会很明显。如果是在Internet上测试,改善的效果应该会比较明显。

 

 

 

 

 

附上源码

/** Copyright 2003 Jayson Falkner (jayson@jspinsider.com)* This code is from "Servlets and JavaServer pages; the J2EE Web Tier",* http://www.jspbook.com. You may freely use the code both commercially* and non-commercially. If you like the code, please pick up a copy of* the book and help support the authors, development of more free code,* and the JSP/Servlet/J2EE community.*/
package cn.javass.common.web.filter;/*使用gzip优化web应用(filter实现)*/
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.IOException;public class GZIPFilter implements Filter {private static Logger log = LoggerFactory.getLogger(GZIPFilter.class);public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {if (req instanceof HttpServletRequest) {HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) res;String ae = request.getHeader("accept-encoding");if (ae != null && ae.indexOf("gzip") != -1) {log.debug("GZIP supported, compressing.");GZIPResponseWrapper wrappedResponse = new GZIPResponseWrapper(response);chain.doFilter(req, wrappedResponse);wrappedResponse.finishResponse();return;}chain.doFilter(req, res);}}public void init(FilterConfig filterConfig) {// noop
    }public void destroy() {// noop
    }
}
/** Copyright 2003 Jayson Falkner (jayson@jspinsider.com)* This code is from "Servlets and JavaServer pages; the J2EE Web Tier",* http://www.jspbook.com. You may freely use the code both commercially* and non-commercially. If you like the code, please pick up a copy of* the book and help support the authors, development of more free code,* and the JSP/Servlet/J2EE community.*/
package cn.javass.common.web.filter;import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;public class GZIPResponseStream extends ServletOutputStream {protected ByteArrayOutputStream baos = null;protected GZIPOutputStream gzipstream = null;protected boolean closed = false;protected HttpServletResponse response = null;protected ServletOutputStream output = null;public GZIPResponseStream(HttpServletResponse response) throws IOException {super();closed = false;this.response = response;this.output = response.getOutputStream();baos = new ByteArrayOutputStream();gzipstream = new GZIPOutputStream(baos);}@Overridepublic void close() throws IOException {if (closed) {throw new IOException("This output stream has already been closed");}gzipstream.finish();byte[] bytes = baos.toByteArray();//   response.addHeader("Content-Length", Integer.toString(bytes.length));response.addHeader("Content-Encoding", "gzip");output.write(bytes);output.flush();output.close();closed = true;}@Overridepublic void flush() throws IOException {if (closed) {throw new IOException("Cannot flush a closed output stream");}gzipstream.flush();}@Overridepublic void write(int b) throws IOException {if (closed) {throw new IOException("Cannot write to a closed output stream");}gzipstream.write((byte) b);}@Overridepublic void write(byte b[]) throws IOException {write(b, 0, b.length);}@Overridepublic void write(byte b[], int off, int len) throws IOException {if (closed) {throw new IOException("Cannot write to a closed output stream");}gzipstream.write(b, off, len);}public boolean closed() {return (this.closed);}public void reset() {//noop
    }
}
/** Copyright 2003 Jayson Falkner (jayson@jspinsider.com)* This code is from "Servlets and JavaServer pages; the J2EE Web Tier",* http://www.jspbook.com. You may freely use the code both commercially* and non-commercially. If you like the code, please pick up a copy of* the book and help support the authors, development of more free code,* and the JSP/Servlet/J2EE community.*/
package cn.javass.common.web.filter;import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;public class GZIPResponseWrapper extends HttpServletResponseWrapper {protected HttpServletResponse origResponse = null;protected ServletOutputStream stream = null;protected PrintWriter writer = null;public GZIPResponseWrapper(HttpServletResponse response) {super(response);origResponse = response;}public ServletOutputStream createOutputStream() throws IOException {return (new GZIPResponseStream(origResponse));}public void finishResponse() {try {if (writer != null) {writer.close();}else {if (stream != null) {stream.close();}}}catch (IOException e) {}}@Overridepublic void flushBuffer() throws IOException {stream.flush();}@Overridepublic ServletOutputStream getOutputStream() throws IOException {if (writer != null) {throw new IllegalStateException("getWriter() has already been called!");}if (stream == null) stream = createOutputStream();return (stream);}@Overridepublic PrintWriter getWriter() throws IOException {if (writer != null) {return (writer);}if (stream != null) {throw new IllegalStateException("getOutputStream() has already been called!");}stream = createOutputStream();writer = new PrintWriter(new OutputStreamWriter(stream, "UTF-8"));return (writer);}@Overridepublic void setContentLength(int length) {}
}

web.xml

                <!--GZIP文件压缩的应用  --><filter><filter-name>GZIPFilter</filter-name><filter-class>cn.javass.common.web.filter.GZIPFilter</filter-class></filter><filter-mapping><filter-name>GZIPFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/545152.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

肯德尔相关性分析_肯德尔的Tau机器学习相关性

肯德尔相关性分析Before we begin I hope you guys have a basic understanding of Pearson’s and Spearmans correlation. As the name suggests this correlation was named after Maurice Kendall in the year 1938. 在开始之前&#xff0c;我希望你们对皮尔逊和斯皮尔曼的…

40 张图带你搞懂 TCP 和 UDP

我们本篇文章的组织脉络如下运输层位于应用层和网络层之间&#xff0c;是 OSI 分层体系中的第四层&#xff0c;同时也是网络体系结构的重要部分。运输层主要负责网络上的端到端通信。运输层为运行在不同主机上的应用程序之间的通信起着至关重要的作用。下面我们就来一起探讨一下…

android手机两种方式获取IP地址

http://www.cnblogs.com/android100/p/Android-get-ip.html 1.使用WIFI 首先设置用户权限 Xml代码 <uses-permission android:name"android.permission.ACCESS_WIFI_STATE"></uses-permission> <uses-permission android:name"android.permi…

进程、线程、多线程相关总结

进程、线程、多线程相关总结 一、说说概念 1、进程&#xff08;process&#xff09; 狭义定义&#xff1a;进程就是一段程序的执行过程。 广义定义&#xff1a;进程是一个程序关于某个数据集合的一次运行。它是操作系统动态执行的基本单元&#xff0c;在传统的操作系统中&#…

z字扫描和光栅扫描的转换_扫描转换计算机图形中的直线

z字扫描和光栅扫描的转换扫描转换直线 (Scan Converting a Straight Line) For the scan conversion of a straight line, we need the two endpoints. In normal life, if we want to draw a line we simply draw it by using a scale or ruler. But we cant draw a line on t…

TextView 单行显示长文本

android:singleLine"true"//单行显示 android:ellipsize"end"//省略号出现在末尾 http://blog.csdn.net/wxg630815/article/details/8996091

腾讯推出高性能 RPC 开发框架

Tars是基于名字服务使用Tars协议的高性能RPC开发框架&#xff0c;同时配套一体化的服务治理平台&#xff0c;帮助个人或者企业快速的以微服务的方式构建自己稳定可靠的分布式应用。Tars是将腾讯内部使用的微服务架构TAF&#xff08;Total Application Framework&#xff09;多年…

Failed connect to github.com:443; No error

任务目标&#xff1a;将线上已有的https://github.com/eyjian/mooon.git克隆到本地的E:\GitHub\mooon目录问题描述&#xff1a;使用Git的Windows客户端UI工具GitHub执行克隆操作时报错&#xff0c;查看它的日志&#xff0c;难发现问题&#xff0c;于是改用Git的Windows命令行终…

python 程序耗时记录_Python学校的学生身高记录程序

python 程序耗时记录A team of 5 people is assigned with a task to record the heights of students in a school and they have decided to make a python program using class to record all the students height. 由5人组成的小组负责记录学校中学生的身高&#xff0c;他…

看完这篇文章,我再也不怕面试官问「垃圾回收」了...

前言 Java 相比 C/C 最显著的特点便是引入了自动垃圾回收 (下文统一用 GC 指代自动垃圾回收)&#xff0c;它解决了 C/C 最令人头疼的内存管理问题&#xff0c;让程序员专注于程序本身&#xff0c;不用关心内存回收这些恼人的问题&#xff0c;这也是 Java 能大行其道的重要原因之…

react从不会到入门

react从不会到入门1_react初识1.1_react基础环境搭建1.2_文件目录介绍1.2_JSX基础1.2.1_JSX介绍1.2.2_JSX表达式1.2.3_列表渲染1.2.4_条件渲染1.2.5_函数调用1.2.6_样式控制2_组件基础2.1_函数组件2.2_点击事件3_组件通讯3.1_父子关系4_生命周期4.1_挂载阶段4.2_更新阶段5_Hook…

Windows系统端口转发

1、添加端口转发 netsh interface portproxy add v4tov4 listenport10001 listenaddress192.168.1.100 connectport10001 connectaddress192.168.1.105 2、删除端口转发 netsh interface portproxy del v4tov4 listenport10001 listenaddress192.168.1.100 3、查看已存在的端口…

Microsoft Dynamics CRM 数据库连接存储位置在哪里 是在注册表里

Microsoft Dynamics CRM 数据库连接存储位置是在注册表里

将所有文件从目录复制到Python中的另一个目录

shutil (shell utilities) module, provides option to copy the files recursively from src to dst. shutil(shell实用程序)模块 &#xff0c;提供了将文件从src递归复制到dst的选项 。 The syntax to copy all files is: 复制所有文件的语法为&#xff1a; shutil.copytre…

Redis的8大数据类型,写的真好

来源 | blog.itzhouq.cn/redis2最近这几天的面试每一场都问到了&#xff0c;但是感觉回答的并不好&#xff0c;还有很多需要梳理的知识点&#xff0c;这里通过几篇 Redis 笔记整个梳理一遍。Redis 的八大数据类型官网可查看命令&#xff1a;http://www.redis.cn/commands.htmlR…

前后端(react+springboot)服务器部署

前后端&#xff08;reactspringboot&#xff09;服务器部署1_前端reactumi服务器部署1.1_前端生成dist目标文件1.2_准备连接服务器的工具1.3_安装nginx1.4_部署项目1.4.1_传输dist文件1.4.2_配置配置文件1.4.3_启动nginx2_后端springboot项目部署服务器2.1_后端生成目标文件2.2…

关于CentOS-6的默认带的mysql启动和安装问题

一开始想自己一步一步从编译开始搭建一个lanmp环境&#xff1b;从鸟哥的linux看到可以不用自己去安装&#xff0c;默认的可能更稳定&#xff0c;所以就开始探索系统自带的mysql和其他的工具&#xff0c;在mysql启动的时候遇到了问题。问题&#xff1a;默认的系统中根本就没有 【…

【LeetCode从零单排】No 191.Number of 1 Bits(考察位运算)

题目 Write a function that takes an unsigned integer and returns the number of ’1 bits it has (also known as the Hamming weight). For example, the 32-bit integer ’11 has binary representation 00000000000000000000000000001011, so the function should retur…

提高生产力,最全 MyBatisPlus 讲解!

如果你每天还在重复写 CRUD 的 SQL&#xff0c;如果你对这些 SQL 已经不耐烦了&#xff0c;那么你何不花费一些时间来阅读这篇文章&#xff0c;然后对已有的老项目进行改造&#xff0c;必有收获&#xff01;一、MP 是什么MP 全称 Mybatis-Plus &#xff0c;套用官方的解释便是成…

c#象棋程序_C ++程序确定象棋方块的颜色

c#象棋程序A chess board is equally divided into 64 identical squares that are black and white alternately. Each square on the chessboard can be identified by the coordinates as A to H on the horizontal axis and 1 to 8 on the vertical axis as shown in the f…