码迷,mamicode.com
首页 > 编程语言 > 详细

【spring】通过GZIP压缩提高网络传输效率(可以实现任何资源的gzip压缩、包括AJAX)

时间:2015-02-28 16:30:20      阅读:237      评论:0      收藏:0      [点我收藏+]

标签:



【spring】通过GZIP压缩提高网络传输效率(可以实现任何资源的gzip压缩、包括AJAX)


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


1、通过WEB服务器打开GZIP压缩服务

      目前大多数主流WEB中间件都支持GZIP压缩、下面以Tomcat 为例进行说明:

      找到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"

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

      <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" >

      一般文本类型的静态文件可以通过这种方式压缩后传输、提高传输效率。

      已压缩过的静态文件(如图片)进行gzip压缩后大小基本无变化、所以一般不进行压缩。


2、通过过滤器实现gzip压缩

package com.tyyd.framework.web;
 
import java.io.IOException;

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;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;

import com.tyyd.framework.core.AcwsInfo;
import com.tyyd.framework.core.AcwsMonitorLog;
import com.tyyd.framework.core.BufferedResponse;
import com.tyyd.framework.core.util.ZipUtil;
 
/**
 * HTTP访问过滤器
 */
public class PageVisitFilter2 implements Filter {
 
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
 
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    	//性能监控
    	long startTime = System.currentTimeMillis();
    			
    	HttpServletRequest request = (HttpServletRequest)req;
    	HttpServletResponse response = (HttpServletResponse)res;
    	
    	String uri = request.getRequestURI();
    	String ext = FilenameUtils.getExtension(uri);
    	
    	try{
			response.setHeader("Pragma", "No-cache");
			response.setHeader("Cache-Control", "no-cache");
			response.setDateHeader("Expires", -1);
			request.setCharacterEncoding("UTF-8");
			response.setCharacterEncoding("UTF-8");
			
			response.setHeader("renderer", "webkit"); 
			response.setHeader("viewport", "width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0 user-scalable=no"); 
	
	    	if(isGZipEncoding(request)){
	    		//需要过滤的扩展名:.htm,.html,.jsp,.js,.ajax,.css
	    		String gzippPattern=",.htm,.html,.jsp,.js,.ajax,.css,";
	    		if(StringUtils.indexOf(gzippPattern, ",."+ext+",")!=-1){
	                BufferedResponse gzipResponse = new BufferedResponse(response);
	                chain.doFilter(request, gzipResponse);
	                byte[] srcData = gzipResponse.getResponseData();
	                byte[] outData = null;
	                if(srcData.length > 512){
						byte[] gzipData = ZipUtil.toGzipBytes(srcData);
						response.addHeader("Content-Encoding", "gzip");
						response.setContentLength(gzipData.length);
						outData = gzipData;
	                } else {
	                	outData = srcData;
	                }
	                ServletOutputStream output = response.getOutputStream();
	                output.write(outData);
	                output.flush();    			
	    		} else {
	    			chain.doFilter(request, response);
	    		}
	    		return;
	    	}
	    	
	        chain.doFilter(request, response);
    	}catch(Exception e){
        
    	}finally{
    		AcwsMonitorLog.warnHttpVisit(startTime, request);
    	}
    }
 
    @Override
    public void destroy() {
    }
    
    /**
     * 判断浏览器是否支持GZIP
     * @param request
     * @return 
     */
    private boolean isGZipEncoding(HttpServletRequest request){
      boolean flag=false;
      String encoding=request.getHeader("Accept-Encoding");
      if(encoding.indexOf("gzip")!=-1){
        flag=true;
      }
      return flag;
    } 
}


package com.tyyd.framework.core;


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 BufferedResponse extends HttpServletResponseWrapper {
	public static final int OT_NONE = 0, OT_WRITER = 1, OT_STREAM = 2;
	
	private BufferedOutputStream outputStream = null;
	private PrintWriter writer = null;
	private int outputType = OT_NONE;

	public BufferedResponse(HttpServletResponse response) {
		super(response);
		outputStream = new BufferedOutputStream();
	}
	
    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(outputStream,
			        getCharacterEncoding()), true);
            return writer;
        }
    }
    
	public ServletOutputStream getOutputStream() throws IOException {
        if (outputType == OT_WRITER)
            throw new IllegalStateException();
        else if (outputType == OT_STREAM)
            return outputStream;
        else {
            outputType = OT_STREAM;
            return outputStream;
        }
    }
    public void flushBuffer() throws IOException {
        try{writer.flush();}catch(Exception e){}
        try{outputStream.flush();}catch(Exception e){}
    }

    public void reset() {
        outputType = OT_NONE;
        outputStream.reset();
    }

    public byte[] getResponseData() throws IOException {
        flushBuffer();
        return outputStream.toByteArray();
    }
}

/**
 * 版权所有:
 * 项目名称:框架
 * 创建者: Wangdf
 * 创建日期: 2015-2-27
 * 文件说明: AJAX 缓存输出流
 */
package com.tyyd.framework.core;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

import javax.servlet.ServletOutputStream;

public class BufferedOutputStream extends ServletOutputStream {
	private ByteArrayOutputStream outputStream = null;

	public BufferedOutputStream(){
		outputStream = new ByteArrayOutputStream(1024);
	}
	
	
    /**
     * Writes the specified byte to this output stream. The general 
     * contract for <code>write</code> is that one byte is written 
     * to the output stream. The byte to be written is the eight 
     * low-order bits of the argument <code>b</code>. The 24 
     * high-order bits of <code>b</code> are ignored.
     * <p>
     * Subclasses of <code>OutputStream</code> must provide an 
     * implementation for this method. 
     *
     * @param      b   the <code>byte</code>.
     * @exception  IOException  if an I/O error occurs. In particular, 
     *             an <code>IOException</code> may be thrown if the 
     *             output stream has been closed.
     */
	public void write(int b) throws IOException {
		outputStream.write(b);
	}

    /**
     * Writes <code>b.length</code> bytes from the specified byte array 
     * to this output stream. The general contract for <code>write(b)</code> 
     * is that it should have exactly the same effect as the call 
     * <code>write(b, 0, b.length)</code>.
     *
     * @param      b   the data.
     * @exception  IOException  if an I/O error occurs.
     * @see        java.io.OutputStream#write(byte[], int, int)
     */
    public void write(byte b[]) throws IOException {
    	outputStream.write(b);
    }

    /**
     * Writes <code>len</code> bytes from the specified byte array 
     * starting at offset <code>off</code> to this output stream. 
     * The general contract for <code>write(b, off, len)</code> is that 
     * some of the bytes in the array <code>b</code> are written to the 
     * output stream in order; element <code>b[off]</code> is the first 
     * byte written and <code>b[off+len-1]</code> is the last byte written 
     * by this operation.
     * <p>
     * The <code>write</code> method of <code>OutputStream</code> calls 
     * the write method of one argument on each of the bytes to be 
     * written out. Subclasses are encouraged to override this method and 
     * provide a more efficient implementation. 
     * <p>
     * If <code>b</code> is <code>null</code>, a 
     * <code>NullPointerException</code> is thrown.
     * <p>
     * If <code>off</code> is negative, or <code>len</code> is negative, or 
     * <code>off+len</code> is greater than the length of the array 
     * <code>b</code>, then an <tt>IndexOutOfBoundsException</tt> is thrown.
     *
     * @param      b     the data.
     * @param      off   the start offset in the data.
     * @param      len   the number of bytes to write.
     * @exception  IOException  if an I/O error occurs. In particular, 
     *             an <code>IOException</code> is thrown if the output 
     *             stream is closed.
     */
    public void write(byte b[], int off, int len) throws IOException {
    	outputStream.write(b, off, len);
    }
    /**
     * Writes a <code>String</code> to the client, 
     * without a carriage return-line feed (CRLF) 
     * character at the end.
     *
     *
     * @param s			the <code>String</code> to send to the client
     *
     * @exception IOException 	if an input or output exception occurred
     *
     */
    public void print(String s) throws IOException {
    	print(s, "UTF-8");
    }

    public void print(String s, String charsetName) throws IOException {
    	/*
    	 * 解决中文乱码问题
    	 */
    	outputStream.write(s.getBytes(charsetName));
    }



    /**
     * Writes a <code>boolean</code> value to the client,
     * with no carriage return-line feed (CRLF) 
     * character at the end.
     *
     * @param b			the <code>boolean</code> value 
     *				to send to the client
     *
     * @exception IOException 	if an input or output exception occurred
     *
     */

    public void print(boolean b) throws IOException {
    	print(b?"true":"false");
    }



    /**
     * Writes a character to the client,
     * with no carriage return-line feed (CRLF) 
     * at the end.
     *
     * @param c			the character to send to the client
     *
     * @exception IOException 	if an input or output exception occurred
     *
     */

    public void print(char c) throws IOException {
    	print(String.valueOf(c));
    }

    /**
     *
     * Writes an int to the client,
     * with no carriage return-line feed (CRLF) 
     * at the end.
     *
     * @param i			the int to send to the client
     *
     * @exception IOException 	if an input or output exception occurred
     *
     */  

    public void print(int i) throws IOException {
    	print(String.valueOf(i));
    }



 
    /**
     * 
     * Writes a <code>long</code> value to the client,
     * with no carriage return-line feed (CRLF) at the end.
     *
     * @param l			the <code>long</code> value 
     *				to send to the client
     *
     * @exception IOException 	if an input or output exception 
     *				occurred
     * 
     */

    public void print(long l) throws IOException {
    	print(String.valueOf(l));
    }



    /**
     *
     * Writes a <code>float</code> value to the client,
     * with no carriage return-line feed (CRLF) at the end.
     *
     * @param f			the <code>float</code> value
     *				to send to the client
     *
     * @exception IOException	if an input or output exception occurred
     *
     *
     */

    public void print(float f) throws IOException {
    	print(String.valueOf(f));
    }



    /**
     *
     * Writes a <code>double</code> value to the client,
     * with no carriage return-line feed (CRLF) at the end.
     * 
     * @param d			the <code>double</code> value
     *				to send to the client
     *
     * @exception IOException 	if an input or output exception occurred
     *
     */

    public void print(double d) throws IOException {
    	print(String.valueOf(d));
    }



    /**
     * Writes a carriage return-line feed (CRLF)
     * to the client.
     *
     *
     *
     * @exception IOException 	if an input or output exception occurred
     *
     */

    public void println() throws IOException {
    	print("\r\n");
    }



    /**
     * Writes a <code>String</code> to the client, 
     * followed by a carriage return-line feed (CRLF).
     *
     *
     * @param s			the <code>String</code> to write to the client
     *
     * @exception IOException 	if an input or output exception occurred
     *
     */
    public void println(String s){
    	println(s, "UTF-8");
    }
    public void println(String s, String charsetName){
    	/*
    	 * 解决中文乱码问题
    	 */
    	try {
    		print(s,charsetName);
			println();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
    }




    /**
     *
     * Writes a <code>boolean</code> value to the client, 
     * followed by a 
     * carriage return-line feed (CRLF).
     *
     *
     * @param b			the <code>boolean</code> value 
     *				to write to the client
     *
     * @exception IOException 	if an input or output exception occurred
     *
     */

    public void println(boolean b) throws IOException {
    	print(b);
    	println();
    }



    /**
     *
     * Writes a character to the client, followed by a carriage
     * return-line feed (CRLF).
     *
     * @param c			the character to write to the client
     *
     * @exception IOException 	if an input or output exception occurred
     *
     */

    public void println(char c) throws IOException {
    	print(c);
    	println();
    }



    /**
     *
     * Writes an int to the client, followed by a 
     * carriage return-line feed (CRLF) character.
     *
     *
     * @param i			the int to write to the client
     *
     * @exception IOException 	if an input or output exception occurred
     *
     */

    public void println(int i) throws IOException {
    	print(i);
    	println();
    }



    /**  
     *
     * Writes a <code>long</code> value to the client, followed by a 
     * carriage return-line feed (CRLF).
     *
     *
     * @param l			the <code>long</code> value to write to the client
     *
     * @exception IOException 	if an input or output exception occurred
     *
     */  

    public void println(long l) throws IOException {
    	print(l);
    	println();
    }



    /**
     *
     * Writes a <code>float</code> value to the client, 
     * followed by a carriage return-line feed (CRLF).
     *
     * @param f			the <code>float</code> value 
     *				to write to the client
     *
     *
     * @exception IOException 	if an input or output exception 
     *				occurred
     *
     */

    public void println(float f) throws IOException {
    	print(f);
    	println();
    }



    /**
     *
     * Writes a <code>double</code> value to the client, 
     * followed by a carriage return-line feed (CRLF).
     *
     *
     * @param d			the <code>double</code> value
     *				to write to the client
     *
     * @exception IOException 	if an input or output exception occurred
     *
     */

    public void println(double d) throws IOException {
    	print(d);
    	println();
    }
    /**
     * Flushes this output stream and forces any buffered output bytes 
     * to be written out. The general contract of <code>flush</code> is 
     * that calling it is an indication that, if any bytes previously 
     * written have been buffered by the implementation of the output 
     * stream, such bytes should immediately be written to their 
     * intended destination.
     * <p>
     * If the intended destination of this stream is an abstraction provided by
     * the underlying operating system, for example a file, then flushing the
     * stream guarantees only that bytes previously written to the stream are
     * passed to the operating system for writing; it does not guarantee that
     * they are actually written to a physical device such as a disk drive.
     * <p>
     * The <code>flush</code> method of <code>OutputStream</code> does nothing.
     *
     * @exception  IOException  if an I/O error occurs.
     */
    public void flush() throws IOException {
    	outputStream.flush();
    }

    /**
     * Closes this output stream and releases any system resources 
     * associated with this stream. The general contract of <code>close</code> 
     * is that it closes the output stream. A closed stream cannot perform 
     * output operations and cannot be reopened.
     * <p>
     * The <code>close</code> method of <code>OutputStream</code> does nothing.
     *
     * @exception  IOException  if an I/O error occurs.
     */
    public void close() throws IOException {
    	outputStream.close();
    }
    
    /**
     * Resets the <code>count</code> field of this byte array output 
     * stream to zero, so that all currently accumulated output in the 
     * output stream is discarded. The output stream can be used again, 
     * reusing the already allocated buffer space. 
     *
     * @see     java.io.ByteArrayInputStream#count
     */
    public void reset() {
    	outputStream.reset();
    }
    
    public byte[] toByteArray() {
        return outputStream.toByteArray();
    }
}

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

 

<filter>
  <filter-name>Page Visit Filter</filter-name>
  <filter-class>com.tyyd.framework.web.PageVisitFilter</filter-class> 
 </filter>

 <filter-mapping>
  <filter-name>Page Visit Filter</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>


3、AJAX也可以通过这种方式压缩

只需知道ajax请求的后缀添加到下面的代码中即可:

//需要过滤的扩展名:.htm,.html,.jsp,.js,.ajax,.css

String gzippPattern=",.htm,.html,.jsp,.js,.ajax,.css,";






【spring】通过GZIP压缩提高网络传输效率(可以实现任何资源的gzip压缩、包括AJAX)

标签:

原文地址:http://blog.csdn.net/szwangdf/article/details/43984773

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!