(转载http://blog.csdn.net/hylclxy/article/details/7779662)

出于节约流量考虑, 客户端在向服务端发送request的时候对post数据进行gzip压缩, 同时服务端把返回的数据也进行gzip压缩. 为防止遗忘, 记录在此.

编写工具类GzipUtil.java, 开始没考虑好, 方法实现得较乱:

  1.     public static String METHOD_POST = "POST";
    public static final String ACCEPT_ENCODING = "Accept-Encoding";
    public static final String CONTENT_ENCOING = "Content-Encoding";
    public static final String CONTENT_LENGTH = "Content-Length";
    public static final String ENCODING_GZIP = "gzip";
    public static final String MIME_APPLICATION_X_GZIP = "application/x-gzip";
    public static final String ENCODING = "UTF-8"; /**
    * 对参数进行gzip压缩操作, 返回字节数组
    * @param data 待压缩的字节数组
    * @return 压缩后的gzip字节数组
    * @throws IOException
    */
    public static byte[] gzip(byte[] data) throws IOException{ ByteArrayOutputStream baos = new ByteArrayOutputStream(); GZIPOutputStream gos = new GZIPOutputStream(baos); gos.write(data); gos.finish();
    gos.flush(); byte[] result = baos.toByteArray(); baos.flush(); try{
    gos.close();
    }catch(IOException e){
    logger.warn("Close GZIPOutputStream fail:", e);
    } return result;
    } /**
    * 对参数进行gzip压缩操作, 结果输出到参数的输出流中
    * @param data 待压缩的字节数组
    * @param os 压缩后的输出流
    * @throws IOException
    */
    public static void gzip(byte[] data, OutputStream os) throws IOException{ GZIPOutputStream gos = new GZIPOutputStream(os); gos.write(data); gos.finish();
    gos.flush(); try{
    gos.close();
    }catch(IOException e){
    logger.warn("Close GZIPOutputStream fail:", e);
    } } /**
    * 对输入流进行gzip压缩
    * @param ins 待压缩的输入流
    * @param os 压缩后的输出流
    * @throws IOException
    */
    public static void gzip(InputStream ins, OutputStream os) throws IOException{ GZIPOutputStream gos = new GZIPOutputStream(os); int b;
    while((b = ins.read()) != -1){
    gos.write(b);
    } gos.finish();
    gos.flush(); } /**
    * 解压缩
    * @param ins 输入流
    * @return 解压完的数据字节数组
    * @throws IOException
    */
    public static byte[] unGzip(InputStream ins) throws IOException{ if(logger.isInfoEnabled()){
    logger.info("Start to ungzip parameters.....");
    } GZIPInputStream gis = new GZIPInputStream(ins);
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); int b;
    while((b = gis.read()) != -1){
    baos.write(b);
    } byte[] result = baos.toByteArray(); if(logger.isInfoEnabled()){
    logger.info("Ungzip parameters bytes OK, result bytes size is: " + result.length);
    } try{
    gis.close();
    }catch(IOException e){
    logger.warn("Close GZIPInputStream fail:", e);
    } return result;
    } /**
    * 对输入流的数据解压缩
    * @param ins 待解压的输入流
    * @param os 解压后的输出流
    * @throws IOException
    */
    public static void unGzip(InputStream ins, OutputStream os) throws IOException{ GZIPInputStream gis = new GZIPInputStream(ins); int b;
    while((b = gis.read()) != -1){
    os.write(b);
    } try{
    gis.close();
    }catch(IOException e){
    logger.warn("Close GZIPInputStream fail:", e);
    }
    } /**
    * 把从gzip流中解压出来的参数和request原有的参数合并成一个新Map返回
    *
    * 客户端传来的数据没有经过url编码, 不需要解码
    * @param data 解压后的字节数组
    * @param res 请求的request
    * @return 完整的parameterMap
    * @throws UnsupportedEncodingException
    */
    public static Map<String, Object> getParameterMap(byte[] data, ServletRequest request) throws UnsupportedEncodingException{
    String body = null; if(data != null && data.length > 0){
    body = new String(data, ENCODING);
    } if(body != null && !"".equals(body.trim())){ if(logger.isInfoEnabled()){
    logger.info("Ungzip parameters string is : " + body);
    } //新parameterMap
    Map<String, Object> paramsMap = new LinkedHashMap<String, Object>();
    //把原有parameterMap添加到新map中
    if(request.getParameterMap() != null){
    paramsMap.putAll(request.getParameterMap());
    } String splitMapFlag = "&";
    String spiltKeyValueFlag = "="; String[] mapArr = body.split(splitMapFlag);
    String[] arr = null;
    for(String tagValue : mapArr){
    arr = tagValue.split(spiltKeyValueFlag, 2);
    if(arr.length == 2){
    if(paramsMap.containsKey(arr[0]) && paramsMap.get(arr[0]) != null){
    // List<String> list = new ArrayList<String>();
    // list.addAll(Arrays.asList((String[])paramsMap.get(arr[0])));
    // list.add(arr[1]);
    // paramsMap.put(arr[0], list.toArray(new String[list.size()])); // String[] oldArr = (String[])paramsMap.get(arr[0]);
    // String[] newArr = new String[oldArr.length + 1];
    // System.arraycopy(oldArr, 0, newArr, 0, oldArr.length);
    // newArr[newArr.length - 1] = arr[1];
    // paramsMap.put(arr[0], newArr); String[] array = (String[])paramsMap.get(arr[0]);;
    array = Arrays.copyOf(array, array.length + 1);
    array[array.length - 1] = arr[1];
    paramsMap.put(arr[0], array);
    }else{
    paramsMap.put(arr[0], new String[]{arr[1]});
    }
    }
    }
    return paramsMap;
    } return request.getParameterMap();
    }

修改filter类, 同时兼容不支持gzip压缩的老版本客户端:

  1. //判断返回给客户端的响应流是否是需要经过gzip压缩
    String acceptEncoding = req.getHeader(GZipUtil.ACCEPT_ENCODING);
    if (acceptEncoding != null
    && acceptEncoding.trim().equalsIgnoreCase(GZipUtil.ENCODING_GZIP))
    {
    res.setHeader(GZipUtil.CONTENT_ENCOING, GZipUtil.ENCODING_GZIP);
    GZipResponse gzipResponse = new GZipResponse(res); //contentType为application/x-gzip, 代表客户端压缩了请求参数, 需要解压
    String contentType = req.getContentType();
    if (contentType != null
    && contentType.equalsIgnoreCase(GZipUtil.MIME_APPLICATION_X_GZIP))
    {
    byte[] data = GZipUtil.unGzip(req.getInputStream());
    Map<String, Object> newParameterMap = GZipUtil.getParameterMap(data,
    req);
    RequestParameterWrapper requestWrapper = new RequestParameterWrapper(
    req, newParameterMap);
    chain.doFilter(requestWrapper, gzipResponse);
    }
    else
    {
    chain.doFilter(req, gzipResponse);
    }
    }
    else
    {
    chain.doFilter(request, res);
    }

因为请求内容有被压缩的post参数未正常保存在request中, 建立新类RequestParameterWrapper(继承HttpServletRequestWrapper, 调用gzipUtil的方法处理)重新包装请求参数, 同时使用GZipResponse extends HttpServletResponseWrapper对响应数据进行gzip压缩.

RequestParameterWrapper:

public class RequestParameterWrapper extends HttpServletRequestWrapper
{
private final Map params;
public RequestParameterWrapper(HttpServletRequest request, Map newParams)
{
super(request);
this.params = newParams;
} @Override
public Map getParameterMap(){
return params;
} @Override
public Enumeration getParameterNames(){
Vector l = new Vector(params.keySet());
return l.elements();
} @Override
public String[] getParameterValues(String name){
Object v = params.get(name);
if(v == null){
return null;
}else if(v instanceof String[]){
return (String[])v;
}else if(v instanceof String){
return new String[]{(String)v};
}else{
return new String[]{v.toString()};
}
} @Override
public String getParameter(String name){
Object v = params.get(name);
if(v == null){
return null;
}else if(v instanceof String[]){
return ((String[])v)[0];
}else if(v instanceof String){
return (String)v;
}else{
return v.toString();
}
} }

GZipResponse:

  1. public class GZipResponse extends HttpServletResponseWrapper
    {
    private GZIPServletStream wrappedOut; public GZipResponse(HttpServletResponse response) throws IOException
    {
    super(response);
    wrappedOut = new GZIPServletStream(response);
    } public ServletOutputStream getOutputStream() throws IOException
    {
    return wrappedOut;
    } private PrintWriter wrappedWriter; public PrintWriter getWriter() throws IOException
    {
    if (wrappedWriter == null)
    {
    wrappedWriter = new PrintWriter(new OutputStreamWriter(
    getOutputStream(), getCharacterEncoding()));
    }
    return wrappedWriter;
    } public void flush() throws IOException
    {
    if (wrappedWriter != null)
    {
    wrappedWriter.flush();
    }
    } private class GZIPServletStream extends ServletOutputStream
    {
    private HttpServletResponse response;
    private OutputStream outputStream;
    private ByteArrayOutputStream baos = new ByteArrayOutputStream(); public GZIPServletStream(HttpServletResponse response) throws IOException
    {
    this.response = response;
    outputStream = response.getOutputStream();
    } public void write(byte[] buf) throws IOException
    {
    baos.write(buf);
    } public void write(byte[] buf, int off, int len) throws IOException
    {
    baos.write(buf, off, len);
    } public void write(int c) throws IOException
    {
    baos.write(c);
    } public void write(byte buf) throws IOException
    {
    baos.write(buf);
    } public void flush() throws IOException
    {
    // byte[] bytes = baos.toByteArray();
    // GZipUtil.gzip(bytes, outputStream); //需要把压缩后的字节大小设置到response的content-length中
    byte[] bytes = GZipUtil.gzip(baos.toByteArray());
    outputStream.write(bytes); outputStream.flush();
    response.setHeader(GZipUtil.CONTENT_LENGTH, String.valueOf(bytes.length));
    } public void close() throws IOException
    {
    outputStream.close();
    }
    }
    }

Java Web 减少网络 IO、静态资源磁盘 IO 有效的办法--响应使用 GZIP( 压缩http请求与响应gzip压缩)的更多相关文章

  1. 使用java调用fastDFS客户端进行静态资源文件上传

    一.背景 上篇博客我介绍了FastDFS的概念.原理以及安装步骤,这篇文章我们来聊一聊如何在java中使用FastDFSClient进行静态资源的上传. 二.使用步骤 1.开发环境 spring+sp ...

  2. 013-Spring Boot web【二】静态资源、Servlet、Filter、listenter

    一.静态资源 1.1.webapp默认支持静态资源 在src/main/webapp下建立user.html默认支持访问 1.2.默认内置静态资源目录.可被直接访问 查看包:spring-boot-a ...

  3. [系统资源攻略]IO第一篇-磁盘IO,内核IO概念

    几个基本的概念 在研究磁盘性能之前我们必须先了解磁盘的结构,以及工作原理.不过在这里就不再重复说明了,关系硬盘结构和工作原理的信息可以参考维基百科上面的相关词条--Hard disk drive(英文 ...

  4. idea 修改静态资源不需要重启的办法

    快捷键Ctrl + Alt + S打开设置面板,勾选Build project automatically选项: 快捷键Ctrl + Shift + A查找registry命令: 在查找到的regis ...

  5. SpringMVC中css,js,图片等静态资源被拦截的解决办法

    一.静态资源的存放路径 css,js,图片等静态资源存放在项目的路径必须为 二.html.jsp导入静态资源文件 html.jsp页面中的导入静态资源文件: js: css: 图片: 二.web.xm ...

  6. maven的java web项目启动找不到Spring ContextLoaderListener的解决办法

    用maven搭建的java web项目,上传到git仓库后,当同事clone下来项目,部署到tomcat运行时,就报了如下错误,即启动web项目时,加载web.xml文件,找不到spring的监听器, ...

  7. spring boot jsp里面的静态资源访问不到解决办法

    闲着没事写的小Demo 用到了jsp页面,里面有些静态资源, springboot 默认的静态资源的值有四个:Default: classpath:/META-INF/resources/,class ...

  8. java Web jsp页面的静态包含和动态包含

    现在有头 体 尾 三个jsp页面 top.jsp <%@ page language="java" contentType="text/html; charset= ...

  9. java web jsp原理图 ,静态包含,动态包含,out与response.getWrite()

    jsp原理图 ,静态包含,动态包含,out与response.getWrite() 

随机推荐

  1. 4.scala中的类

    版权申明:转载请注明出处.文章来源:http://bigdataer.net/?p=269 排版乱?请移步原文获得更好的阅读体验 1.针对不同字段生成的方法 字段生成的方法备注 var/val nam ...

  2. Shell脚本 curl获取必应每日壁纸(Mac OS)

    Mac上Safari不能下载壁纸,遇到好看的很想用作壁纸.写了一小段脚本用来拉取网页图片. curl: -sS 参数用来取消下载状态显示 grep 首先把含有图片网址的行提取了出来,针对这一行再做se ...

  3. 在HTTP通讯过程中,是客户端还是服务端主动断开连接?

    比如说:IE访问IIS,获取文件,肯定是要建立一个连接,这个连接在完成通讯后,是客户端Close了连接,还是服务端Close了连接.我用程序测模拟IE和IIS,都没有收到断开连接的消息,也就是都没有触 ...

  4. 使用js合并table中的单元格

    用primefaces做的报表,领导要求合并相同内容的单元格,但是primefaces没有找到可以合并单元格的组件,想来想去,只有页面加载后用js合并了. http://blog.csdn.net/d ...

  5. 终于搞懂了shell bash cmd...

    问题一:DOS与windows中cmd区别 在windows系统中,“开始-运行-cmd”可以打开“cmd.exe”,进行命令行操作. 操作系统可以分成核心(kernel)和Shell(外壳)两部分, ...

  6. C++ 线程的创建、挂起、唤醒和结束 &&&& 利用waitForSingleObject 函数陷入死锁的问题解决

    最近在写一个CAN总线的上位机软件,利用CAN转USB的设备连到电脑上,进行数据的传输.在接收下位机发送的数据的时候采用的在线程中持续接收数据. 1.在连接设备的函数中,开启线程. ,CREATE_S ...

  7. VC中release和debug版本的区别

    DEBUG版本 包含调试信息,编译器生成的代码方便调试 RELEASE版本 算是发布版本,RELEASE下不能调试,生成的文件更小,编译器生成的程序速度更快但是Debug下生成的exe文件在单独运行时 ...

  8. IOS - 前台时的推送弹窗效果

    作者:Pikacode 原文链接:http://www.jianshu.com/p/67864e1c2085 本文获作者授权转载 或许很多童鞋还不知道,在 iOS 中收到推送通知时,如果 App 处于 ...

  9. IOS-涂鸦

    // // PaintView.m // IOS_0224_涂鸦 // // Created by ma c on 16/2/24. // Copyright © 2016年 博文科技. All ri ...

  10. 详解offset

    offset offset 译为“偏移量”,是javascript很重要的一个概念.涉及到便宜量的主要有offsetLeft.offsetTop.offHeight.offsetWidth这四个属性还 ...