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



【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,";

时间: 2024-10-14 14:22:18

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

网页启用Gzip压缩 提高浏览速度

启用Gzip压缩的好处 它的好处显而易见,提高网页浏览速度,无论是之前说的精简代码.压缩图片都不如启用Gzip来的实在.下图为启用Gzip后的效果. Gzip压缩效率非常高,通常可以达到70%的压缩率,也就是说,如果你的网页有30K,压缩之后就变成了9K左右. 第一步:打开IIS,启用HTTP压缩服务 右击“网站”->“属性”,选择“服务”.在“HTTP压缩”框中选中“压缩应用程序文件”和“ 压缩静态文件”,按需要设置“临时目录”和“临时目录的最大限制”; 第二步:启用web服务 第三步:修改M

前端性能优化篇—资源合并与压缩减少HTTP请求

资源合并与压缩减少HTTP请求的概要 资源合并与压缩减少HTTP请求主要的两个优化点是减少HTTP请求的数量和减少请求资源的大小 http协议是无状态的应用层协议,意味着每次http请求都需要建立通信链路.进行数据传输,而在服务器端,每个http都需要启动独立的线程去处理. 这些通信和服务的开销都很昂贵,减少http请求的数量和减少请求资源的大小可有效提高访问性能 减少http的主要手段是合并CSS.合并JavaScript.合并图片.将浏览器一次访问需要的javascript和CSS合并成一个

静态资源文件自动压缩并替换成压缩版本(大型网站优化技术)

原文:静态资源文件自动压缩并替换成压缩版本(大型网站优化技术) 这一次,我总结和分享一项大型网站优化技术,那就是在项目中自动压缩静态资源文件(css.js),并让网站自动加载压缩后的资源文件.当然,这项技术在雅虎35条前端优化建议里也有记载,但它那只是给出一个理论的方案而已,并且采用的是外部压缩工具去压缩,而在我的项目中,是直接通过自己的程序自动化去压缩所有css.js文件,然后让页面直接加载所压缩后的资源,接下来直接进入主题. 本次实验使用的是PHP脚本语言,版本是PHP5.6,是在LINUX

一、资源合并与压缩

在DNS方面?在浏览器层面甚至是路由器层面将DNS服务器相关的信息进行缓存,访问DNS的时间就可以缩短很多. 网络请求?使用CDN,解决了网络选择和缓存的问题,CDN是用于静态资源的,但是网络请求静态资源的时候还是会带上cookie,这时候的cookie其实是对网络的损耗,所以希望在请求静态资源的时候将cookie去掉.CDN的域名与主站不一样就可以让cookie不会携带. 带宽?如何减少一个HTTP请求的大小,也是很重要的一点. react等框架?服务端渲染直出HTML,在服务端进行HTML渲

ASP.NET Core 资源打包与压缩

原文:ASP.NET Core 资源打包与压缩 ASP.NET Core 资源打包与压缩 在ASP.NET 中可以使用打包与压缩来提高Web应用程序页面加载的性能. 打包是将多个文件(CSS,JS等资源文件)合并或打包到单个文件.文件合并可减少Web资源文件从服务器的所需请求数,这样可提高页面载入的性能. 压缩是将各种不同的代码进行优化,以减少请求资源文件的体积.压缩的常见方法删除不必要的空格和注释,并将变量名缩减为一个字符. bundleconfig.json文件 [ { "outputFil

JavaEE学习之Spring Security3.x——模拟数据库实现用户,权限,资源的管理

一.引言 因项目需要最近研究了下Spring Security3.x,并模拟数据库实现用户,权限,资源的管理. 二.准备 1.了解一些Spring MVC相关知识: 2.了解一些AOP相关知识: 3.了解Spring: 4.了解Maven,并安装. 三.实现步骤 本示例中使用的版本是Spring Security3.2.2.通过数据库实现Spring Security认证授权大致需要以下几个步骤: 1.新建maven web project(因为本示例使用的是maven来构建的),项目结构如下,

快压、360压缩、WinRAR关于打开快压通过超高压缩比压缩后的文件不兼容的问题

今天接收了同事发过来的一个压缩文件,用360压缩打开和用WinRAR打开压缩文件,傻眼了,这发的是什么鬼压缩包.压缩包的文件大小有27533KB,用360压缩工具解压查看只有121.5kb,而且完全没有显示出来压缩文件的真实内容,如下所示: 用WinRAR工具解压查看就更加奇葩了,只有一个HTML文件,如下所示: 点击该html文件后,显示的网页内容如下: 好吧,该网页提示我   "由于资源该资源采用了超高压缩比压缩,您当前压缩软件无法进行解压,请下载相应的网页插件,对资源立即进行恢复.&quo

本地和网络获得轮播图资源:

MainActivity: public class MainActivity extends Activity {    Handler hd = new Handler() {        public void handleMessage(android.os.Message msg) {            if (msg.what == 1) {                int currentItem = vp.getCurrentItem();              

uni-app图片压缩转base64位 利用递归来实现多张图片压缩

//选择图片 chooseImage(){ let that =this uni.chooseImage({ sizeType: ['original','compressed'], //可以指定是原图还是压缩图,默认二者都有 count: 9,//默认9 success: (rem) => { console.log(rem) that.tempFilePaths = rem.tempFilePaths; //#ifdef MP-WEIXIN //图片压缩并转base64 that.weixi