使用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压缩到一个纯文本文件时,效果是非常明显的 ...
随机推荐
- 禁用ipv6的两种方法
1 通过系统配置文件/etc/sysctl.conf 在sysctl.conf文件中添加行 # 禁用整个系统所有接口的IPv6 net.ipv6.conf.all.disable_ipv6 = 1 # ...
- PAT乙级:1076 Wifi密码 (15分)
PAT乙级:1076 Wifi密码 (15分) 题干 下面是微博上流传的一张照片:"各位亲爱的同学们,鉴于大家有时需要使用 wifi,又怕耽误亲们的学习,现将 wifi 密码设置为下列数学题 ...
- 五个 .NET 性能小贴士
原文:bit.ly/3wSpO4o 作者:Nikita Starichenko 翻译:精致码农 大家好!今天我想和大家分享几个 .NET 的性能小贴士与基准测试. 我的系统环境: BenchmarkD ...
- proteus8.1 pro 中文版安装破解教程
Proteus8 Pro是非常有名的EDA工具(仿真软件),从原理图布图.代码调试到单片机与外围电路协同仿真,一键切换到PCB设计,真正实现了从概念到产品的完整设计.是唯一将电路仿真软件.PCB设计软 ...
- react踩坑笔记
1.create-react-app中配置webpack // 方法一:将项目的配置文件抽取到项目中,即运行: npm run eject // 方法二:使用react-app-rewired 2.c ...
- leetcode 有效三角形的个数
题目描述: 平明伞兵解法: 既然要求满足三角形要求的三边,简单来说,就是最短两边之和大于第三边,所以,第一步Arrays.sort().先排序,然后直接伞兵暴力法,三重循环.当然最后肯定是能跑出来的, ...
- QML用Instantiator动态创建顶级窗口
关键点 使用Model驱动Instantiator QML里面的hashmap: QQmlPropertyMap 上一次说到用 QQmlApplicationEngine 多次load的方式创建多个一 ...
- Vue学习笔记(二)动态绑定、计算属性和事件监听
目录 一.为属性绑定变量 1. v-bind的基本使用 2. v-bind动态绑定class(对象语法) 3. v-bind动态绑定class(数组语法) 4. v-bind动态绑定style(对象语 ...
- vue日记②之兼容各种情况的可跳转链接
兼容各种情况的可跳转链接 需求 因为聊天气泡颜色原因,发送出去的链接通常模糊不清,而且不能直接跳转,所以我打算已a链接的显示直接抓取所有的网页链接,同时还要兼容富文本框的直接输入图片 这是运行效果 实 ...
- JUC学习笔记(一)
1.什么是 JUC 1.1.JUC简介 在 Java 中,线程部分是一个重点,本篇文章说的 JUC 也是关于线程的.JUC 就是 java.util .concurrent 工具包的简称.这是一个处理 ...