tomcat配置gzip压缩与解压缩

前言

最近的做的项目中,遇到这么一个问题:服务器返回给客户端的xml报文数据量太大,费时耗流量,于是要求服务端添加gzip支持,现在把整个流程写下来,以供以后有需要时参考。gzip是一种文件压缩算法,http服务器端添加支持后,客户端请求时添加请求头信息Accept-Encoding:gzip即可享受服务端的gzip压缩服务,获取压缩后的数据,极大减小网络传输数据,提高响应速度和减少流量。当然,如果客户端http请求中没有添加Accept-Encoding:gzip请求头信息,服务器端返回的依旧是未压缩的数据。

服务端gzip支持

首先,写一个简单的servlet程序,读取一个文本文件,然后返回给客户端
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException {
		String xmlFileName = "books.xml";
		try {
			response.setContentType("text/html;charset=utf-8");
			String filePath=this.getServletConfig().getServletContext().getRealPath("/"+xmlFileName);
			File file = new File(filePath);
			//文件原本大小
			System.out.println("服务端文件大小:"+file.length()+"byte");
			FileInputStream fileIn =new FileInputStream(file);
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			byte[] b = new byte[1024];
			int i = 0;
			while ((i = fileIn.read(b)) != -1) {
				baos.write(b, 0, i);
			}
			ServletOutputStream out = response.getOutputStream();
			out.write(baos.toByteArray());
			out.flush();
			out.close();
			fileIn.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
然后,tomcat配置gzip支持,具体做法是在server.xml配置文件中添加以下属性
    
主要参数解释
compression:开启压缩,可选值:"on"开启,"off"关闭,"force"任何情况都开启
compressionMinSize:指定压缩的最小数据大小,单位B,默认2048B
noCompressionUserAgents:正则表达式,匹配的UA将不会被压缩,默认空
compressableMimeType:会被压缩的MIME类型列表,多个逗号隔开,默认值:text/html,text/xml,text/plain,text/css,text/javascript,application/javascript
具体参考官网: http://tomcat.apache.org/tomcat-7.0-doc/config/http.html

客户端请求及解压缩

首先,通过HttpURLConnection发起请求,看一看未添加Accept-Encoding:gzip请求头的情况,代码如下
	public static void main(String[] args) throws Exception{
		StringBuffer url = new StringBuffer("http://127.0.0.1:8080/GZip/GetBook");
	    URL u = new URL(url.toString()); 
	    HttpURLConnection conn;
	    InputStream in;
	    conn = (HttpURLConnection) u.openConnection();     
	    conn.setRequestMethod("POST");
	    conn.setDoInput(true);
	    conn.setDoOutput(true);
	    in = conn.getInputStream();
	    System.out.println("客户端获取数据大小:"+in.available()+"byte");
	    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
	    String line = null;
	    StringBuffer sb = new StringBuffer();
	    while((line = reader.readLine())!= null){
	    	sb.append(line);
	    }
	    //打印获取到的数据
	    System.out.println(sb.toString());
	    in.close();
	    conn.disconnect();
	}
控制台信息:


数据未压缩,数据大小一致
接着,再来看看添加Accept-Encoding:gzip请求头的情况,在上面的客户端代码添加下面一句
conn.addRequestProperty("Accept-Encoding", "gzip");
请求下:
tomcat配置gzip压缩与解压缩_第1张图片
数据已经被压缩,有原来的8365bB变成258B,gzip格式的数据显示为乱码,所有现在需要做的是对数据进行解压缩,使用JDK自带的GZIPInputStream就能搞定
	    GZIPInputStream gzipIn = new GZIPInputStream(in);
	    BufferedReader reader = new BufferedReader(new InputStreamReader(gzipIn));

结果如下

到此,整个流程基本结束

再插一脚

删除books.xml中的部分数据,使其大小小于配置的最小压缩数据2048B,再次请求,会发现数据不会被压缩

tomcat配置gzip压缩与解压缩_第2张图片
因为数据格式不是gzip压缩格式,所有使用GZIPInputStream解压缩抛异常了
还有一点,浏览器默认请求头包含Accept-Encoding:gzip,而且会自动解压缩,浏览器不会显示乱码,另外,对于请求头中的deflate和gzip类似,也是一种压缩算法,不过多介绍。
tomcat配置gzip压缩与解压缩_第3张图片

插曲

之前通过另一种方式写的服务端发生了件有意思的事,代码如下
			PrintWriter out = response.getWriter();
			BufferedReader br = new BufferedReader(new InputStreamReader(fileIn));
			StringBuffer sb = new StringBuffer();
			String line = null;
			while ((line = br.readLine())!=null){
				sb.append(line);
			}
			out.write(sb.toString());
然后发现客户端的数据大小总比服务端的少了点,找了好久才查出原因。原来是BufferedReader的readLine方法会把每行的回车换行去掉,UTF-8编码下CRLF各占一个字符,所有,数据大小自然变小了。真是浅草才能没马蹄啊,囧。

总结

本文主要写了一个tomcat配置gzip压缩和客户端解压缩的实例,对于不同数据大小下压缩率不尽相同,篇幅有限,不再描述,有兴趣的同学可以自行测试。

你可能感兴趣的:(tomcat配置gzip压缩与解压缩)