使用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压缩到一个纯文本文件时,效果是非常明显的 ...
随机推荐
- 微信小程序云开发-数据库-列表页携带id跳转到详情页
一.新建页面 新建列表页"pages/goodslist/goodslist",新建列表详情页"pages/gooddetail/gooddetail" 二. ...
- Cesium加载地形数据只显示半个地球
Cesium第0级地形包括两个瓦片:0/0/0.terrain,0/1/0.terrain,分别为左半球和右半球(具体参考:https://blog.csdn.net/u013929284/artic ...
- 7.27考试总结(NOIP模拟25)[random·string·queue]
死亡的尽头,没有神 T1 random 解题思路 这波是找规律完胜了.. lby dalao根据样例找出了正确的式子:\(\dfrac{n^2-1}{9}\) 然而,我这个菜鸡却推出了这样一个错误的式 ...
- 第二篇 -- Go语言转义字符与变量声明
上节我们讲了GO语言的环境搭建以及创建了Hello World程序.今天学习一下Go语言基础语法 开发前准备 1. 首先创建一个Project02 2. 在Project02下面新建一个test1.g ...
- PC免费的小说阅读器,可提取章节
最近自己做了个小说阅读器,就是下面这个东西啦,目前仅支持Window系统: 个人喜欢在电脑.平板上等大屏幕设备上阅读小说或电子书籍.原因其一是屏幕足够大,可以选择更舒服的字体大小:其二是觉得小屏幕看字 ...
- GraphPad Prism 9.0安装破解教程
graphpad prism 9.0是一款强大的科学软件,拥有大量分析图表,prism是回归分析的著名软件之一,非常适用于科研生物医学等领域.本文提供其破解版,激活码,序列号,破解教程等,可以完美激活 ...
- Python实用案例,Python脚本,Python实现自动监测Github项目并打开网页
往期回顾 Python实现文件自动归类 前言: 今天我们就利用Python脚本实现Github项目的更新,提醒方式是邮箱.直接开整~ 项目地址: https://github.com/kenwoodj ...
- Serilog 最佳实践
Serilog 最佳实践 概述 Serilog是 Microsoft .NET 的结构化日志记录库,并已成为[Checkout.com .NET 的首选日志记录库..它支持各种日志记录目的地(称为接收 ...
- 直接使用!安装WordPress一键部署轻松建站教程
关于 WordPress WordPress (opens new window)简称WP,最初是一款博客系统,后逐步演化成一款功能强大的企业级 CMS(内容管理/建站系统),目前是公认的全球最佳建站 ...
- noip模拟34[惨败]
noip模拟34 solutions 我从来不为失败找借口,因为败了就是败了,没人听你诉说任何事情 今天很伤感,以来考试没考好,二来改题改半天也改不出来 这次算是炸出来了我经常范的一些错误,比如除以0 ...