欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

全站GZIP压缩过滤的原理及其实现

程序员文章站 2022-03-30 22:57:34
...

  在客户端访问数据时候,为了尽可能高效率的传输,在传输的JSP网页的时候,可以采用GZIP压缩的方式,使得网页经过压缩后再去传输。在此,使用过滤器,对发送到的客户端的显示,都先进行一次压缩。然后再显示,具体流程可以参考下图:

全站GZIP压缩过滤的原理及其实现

也就是说,当每获得一次请求是的时候,通过对getOutputStream的重写,不让其输出到客户端,而是 将其写入到内存字节数组中去。   然后,当需要输出的时候, 也就是过滤器的第二次执行从chain.doFilter(request,response)开始

再次充内存中取出缓存的数据,进行压缩,并用response进行输出。

package cn.Filter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
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;
import javax.servlet.http.HttpServletResponseWrapper;

public class FilterGZIP implements Filter {

	public void destroy() {
		// TODO Auto-generated method stub
	}
	public void doFilter(ServletRequest req, ServletResponse res,
			FilterChain chain) throws IOException, ServletException {
     HttpServletRequest request=(HttpServletRequest) req;
     HttpServletResponse response=(HttpServletResponse) res;
     
     //重新封装response ,来达到改写其已知方法的过程
     MyResponse mresponse=new MyResponse(response);
     
    //以上为过滤器的请求时候的过滤过程;
    //当请求的时候,传入的response 的getOutPutStream方法已经被修改过了。
    //因此,此时如果页面上调用getOutPutStream 方法的时候,其实调用的是自己写的。
     chain.doFilter(request, mresponse);
     
     //请求接受, 开始响应,二次输出的时候,就是开始要将内存中的字节数组,经过压缩传输到客户端的过程了。
     ByteArrayOutputStream  baos =new ByteArrayOutputStream();
     GZIPOutputStream gos=new GZIPOutputStream(baos);
     //从内存中获取到 原始为压缩的数据。
     byte b[]= mresponse.getByte();
     System.out.println("压缩前共有"+b.length+"字节");
     gos.write(b);
     gos.flush();
     gos.close();
     b=baos.toByteArray();
     System.out.println("压缩后共有"+b.length+"字节");
     //设置客户端识别打开的方式。
     response.setHeader("Content-Encoding", "GZIP");
     response.setContentLength(b.length);
     response.getOutputStream().write(b);
	}

	public void init(FilterConfig filterConfig) throws ServletException {
		// TODO Auto-generated method stub

	}

}

以上就是Filter中的全部代码,然后 就是怎样重新封装response的问题了。J2EE中提供了,响应的包装类ServletResponseWrapper    只要继承这个类,重写相应的getOutPutStreaM方法,则目标即刻达成!

class MyResponse extends HttpServletResponseWrapper {
    //这个是用来存放页面要输出信息的字节数组。
    private ByteArrayOutputStream baos=new ByteArrayOutputStream();
     //这个封装的字符流输出对象
    private PrintWriter pw;
    public MyResponse(HttpServletResponse response) {
		super(response);
	}
       //这个方法,很重要,就是用来获取页面信息存放在内存中的字节数组。 也是压缩的目的
	public byte[] getByte() {
		try {
			if(pw!=null){
				pw.flush();
				pw.close();
			}
			baos.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return baos.toByteArray();

	}
	//这个方法,就是我们要重写的方法,但是这个方法,有个返回值ServletOutputStream,而这个类又是个抽象类,所以必须还要把这个类给实现了。可以参考下一个代码块 
	@Override
	public ServletOutputStream getOutputStream() throws IOException {   
		return new MyServletOutputStream(baos);
	}

	@Override
	public PrintWriter getWriter() throws IOException {
		pw= new PrintWriter(new OutputStreamWriter(baos,super.getCharacterEncoding()));
		return pw;
	}
    
}

//这个是应上面getOutPutStream 的邀请的返回值。 也是要 servlet中实际调用的方法。    不会输出到页面,只会将servlet中要写的内容放入到内存中去。
class  MyServletOutputStream extends ServletOutputStream{
     //缓冲页面数据存放区域
    private ByteArrayOutputStream baos;
	public  MyServletOutputStream(ByteArrayOutputStream baos){
		this.baos=baos;
	}
	@Override
	public void write(int b) throws IOException {
		//将输出写入输出缓存
		baos.write(b);
	}
	
}


我自己的理解图形

全站GZIP压缩过滤的原理及其实现


转载于:https://my.oschina.net/anyyang/blog/366216