使用filter过滤GZIP压缩(二)
在代码之前,讲一下用filter实现GZIP压缩的原理:
因为GZIP压缩之后,是从服务器端传输到浏览器端,从servlet到浏览器(从jsp到浏览器),其实是response带回内容,所以我们要在filter中对从servlet端响应回来的response进行操作,因为写内容是response中的writer或者outputStream来完成的,所以我们首先要把response中的writer或者outputStream中的内容取出来,这里我选择了writer进行操作(writer和outputStream其实皆可),但是问题又来了,response.getWriter.write();直接就写出了内容(因为response内部的writer其实是PrintWriter),定位输出到浏览器页面显示上了,并没有缓存起来,那么我们该怎么解决这个问题呢?
思路如下:
使用装饰者模式对response中的getWriter方法进行重写,以便提供一个带缓存的writer,让操作者得到的writer实际上write是定位在writer构造传入的缓存中的(这个缓存可以使用我们之前讲的ByteArrayOutputStream或者CharArrayWriter,这类输出流的好处是,带有一个toByteArray和toCharArray的方法,可以直接获得流内部的内容发)重写HttpServletResponse,同样因为HttpServletResponse只是一个接口,所以要继承自HttpServletResponse的实现类:HttpServletResponseWrapper,(同之前讲过的这篇博文,request和response都是实现wrapper);然后在我们重写之后的response中提供直接获得内部缓存内容的方法,然后我们就可以在filter中正常压缩啦!
servlet中的代码:
package day04;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ContentTestGZIPFilterServlet extends HttpServlet {
private static final long serialVersionUID = 3505039773816640152L;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
// 准备内容
StringBuffer sb = new StringBuffer();
for (int i=1; i<=3000; i++) {
sb.append("abcd");
}
System.out.println("压缩前的数据大小:"+sb.toString().getBytes().length);
// 输出到浏览器
response.getWriter().write(sb.toString());
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
}
}
web.xml中filter的配置:
<filter>
<filter-name>GZIPFilter</filter-name>
<filter-class>day04.GZIPFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>GZIPFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
filter的代码:
package day04;
import java.io.ByteArrayOutputStream;
import java.io.CharArrayWriter;
import java.io.IOException;
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.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
public class GZIPFilter implements Filter {
public void destroy() {}
public void init(FilterConfig filterConfig) throws ServletException {}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//1)过滤请求
//创建一个response的装饰者对象
MyHttpResponse myResponse = new MyHttpResponse((HttpServletResponse)response);
/**
* 放行
*/
chain.doFilter(request, myResponse);
//3)过滤响应
//从缓存容器对象得到压缩前的内容
//注意:response对象中没有方法获取实体内容,怎么办?
char[] content = myResponse.getCharArray();
//gzip压缩
ByteArrayOutputStream buf = new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(buf);
gzip.write(new String(content).getBytes());
gzip.finish();
byte[] result = buf.toByteArray();
//告诉浏览器发送内容的压缩格式
myResponse.setHeader("content-encoding", "gzip");
//输出:
/*
* 注意:
* 这里的输出不能使用PrintWriter了
* 因为PrintWriter的输出定位已经在了内部的流缓存中了,不能定位到界面输出了
* 所以要使用OutputStream
*/
response.getOutputStream().write(result);
//myRresponse.getWriter().write(new String(result,0,result.length));
}
}
/**
* HttpServletResponse的装饰者类
*/
class MyHttpResponse extends HttpServletResponseWrapper{
private HttpServletResponse response;
//定义一个缓存容器对象:必须是自带缓冲的流,不能是包装流:即构造方法还需要传入一个writer的流
CharArrayWriter charArray = new CharArrayWriter();
/**
* 提供一个获取charArray内容的方法
*/
public char[] getCharArray(){
return charArray.toCharArray();
}
public MyHttpResponse(HttpServletResponse response) {
super(response);
this.response = response;
}
/**
* 重写getWriter()方法,让其返回一个带缓存功能的PrintWriter
*/
@Override
public PrintWriter getWriter() throws IOException {
/**
* 现在已经创建了一个带CharArrayWriter缓存容器的PrintWriter了,
* 如果我们调用带缓存PrintWriter对象的write()方法,那么内容会直接写入到CharrArrayWriter缓存容器中。
*/
return new PrintWriter(charArray);
}
}
使用filter过滤GZIP压缩(二)的更多相关文章
- Springboot 之 Filter 实现 Gzip 压缩超大 json 对象
简介 在项目中,存在传递超大 json 数据的场景.直接传输超大 json 数据的话,有以下两个弊端 占用网络带宽,而有些云产品就是按照带宽来计费的,间接浪费了钱 传输数据大导致网络传输耗时较长 为了 ...
- PHP中zlib扩展实现GZIP压缩输出各种方法总结
一般情况下我们出现大量数据传输理希望减少服务器的带宽压力,会采取一种方式来压缩文件传输,php中用zlib也可以实现gzip压缩输出,下面我们来看GZIP压缩输出各种方法总结. GZIP(GNU-ZI ...
- Filter之——GZIP全站压缩
GZIP压缩:将压缩后的文本文件,发送给浏览器,减少流量. 一.进行gzip压缩条件: 1.请求头:Accept-Encoding : gzip 告诉服务器,该浏览器支持gzip压缩. 2.响应头: ...
- JSP Filter,GZIP压缩响应流
url:http://hi.baidu.com/xhftx/blog/item/fbc11d3012648711ebc4af59.html 关键词:JSP,Filter,Servlet,GZIP 现在 ...
- 网站访问优化(二):开启apache服务器gzip压缩
昨天,把带宽从1M升级到2M,使用cdn版本的jquery之后,网站访问速度由平均5s(在禁止缓存的情况下,使用缓存大概在2.8s)下降到2.8s的样子. 今天,继续优化. 第1步: 把图片进行了 ...
- gzip压缩JavaScript
为了提高客户端的体验效果,RIA开发逐渐兴起.这样会项目中会充斥的大量的JavaScript代码,与此同时会消耗客户端浏览器性能.对于 Ext 实现的 one page one application ...
- Apache启用GZIP压缩网页传输方法
一.gzip介绍 Gzip是一种流行的文件压缩算法,如今的应用十分广泛,尤其是在Linux平台.当应用Gzip压缩到一个纯文本文件时,效果是很明显的,大约能够降低70%以上的文件大小.这取决于文件里的 ...
- GZIP压缩提高网络传输效率
[spring]通过GZIP压缩提高网络传输效率(可以实现任何资源的gzip压缩.包括AJAX) gzip是http协议中使用的一种加密算法,客户端向web服务器端发出了请求后,通常情况下服务器端会将 ...
- Apache启用GZIP压缩网页传输
首先我们先了解Apache Gzip的相关资料. 一.gzip介绍 Gzip是一种流行的文件压缩算法,现在的应用十分广泛,尤其是在Linux平台.当应用Gzip压缩到一个纯文本文件时,效果是非常明显的 ...
随机推荐
- Appium - adb monkey参数(三)
monkey 参数 1.常规类参数 A.帮助类参数 monkey -h B.日志级别 $ adb shell monkey -v <event-count> . 2.事件类参数 A .执 ...
- spring-4-申明事务
categories: spring5 事务回顾 事务在项目开发过程非常重要,涉及到数据的一致性的问题,不容马虎! 事务管理是企业级应用程序开发中必备技术,用来确保数据的完整性和一致性. 事务就是把一 ...
- 分布式ID生成器(CosId)的设计与实现
分布式ID生成器(CosId)设计与实现 CosId 简介 CosId 旨在提供通用.灵活.高性能的分布式 ID 生成器. 目前提供了俩类 ID 生成器: SnowflakeId : 单机 TPS 性 ...
- 【系统学习ES6】新专题发布
我要发免费专题了,向下看 公众号和博客都有一阵没更新了,丢了一些粉儿,但是也很庆幸,时时还会有人关注.我并不是什么专业讲师,文章都是利用业余时间手工原创.在这里非常感谢各位的支持和厚爱. 这个月开始, ...
- CSP-S 2020
游记 Day# 游记个鬼啊就在自家学校=-= 早上宿舍待不了,去机房颓废,看了几集猫和老鼠,并且把看门狗军团的流程看完了(真棒),甚至在考试之前把老师给的巧克力也吃完了. 期间zyt学长来摸鱼.他们今 ...
- 01_什么是BS结构,什么是CS结构?
C/S和B/S都是互联网中常见的网络结构模型. 一.什么是C/S模型? C是英文单词"Client"的首字母,即客户端的意思,C/S就是"Client/Server&qu ...
- kivy中文编程指南
Kivy中文编程指南,由网友翻译后,我整理目录及页面形式,便了浏览查阅. 点击下载
- DASCTF七月赛两道Web题复现
Ezfileinclude(目录穿越) 拿到http://183.129.189.60:10012/image.php?t=1596121010&f=Z3F5LmpwZw== t是时间,可以利 ...
- GitHub不再支持密码验证解决方案:SSH免密与Token登录配置
今天提交代码,push到GitHub上,突然出现这个问题. remote: Support for password authentication was removed on August 13, ...
- Java-SpringBoot注解方式实现AOP
AOP基本总结 连接点(JoinPoint): 连接点是程序运行的某个阶段点,如方法调用.异常抛出等 切入点(Pointcut): 切入点是JoinPoint的集合 是程序中需要注入Advice的位置 ...