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

(转载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:

[java] view plaincopy

  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();
            }
        }
    }  
时间: 2024-10-12 04:49:37

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

Java Web学习(2):静态网页与动态网页

一静态网页 (1)静态网页概述 在网站设计中,纯粹HTML(标准通用标记语言下的一个应用)格式的网页通常被称为"静态网页",静态网页是 标准的HTML文件,它的文件扩展名是.htm..html,可以包含文本.图像.声音.FLASH动画.客户端脚本和ActiveX 控件及JAVA小程序等.静态网页是网站建设的基础,早期的网站一般都是由静态网页制作的. 静态网页是相对于动态网页而言,是指没有后台数据库.不含程序和不可交互的网页.静态网页相对更新起来比 较麻烦,适用于一般更新较少的展示型网站

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

一.静态资源 1.1.webapp默认支持静态资源 在src/main/webapp下建立user.html默认支持访问 1.2.默认内置静态资源目录.可被直接访问 查看包:spring-boot-autoconfigure-1.5.9.RELEASE.jar下的:org.springframework.boot.autoconfigure.web; 查看:ResourceProperties,其中 private static final String[] CLASSPATH_RESOURCE

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

快捷键Ctrl + Alt + S打开设置面板,勾选Build project automatically选项: 快捷键Ctrl + Shift + A查找registry命令: 在查找到的registry命令通过鼠标双击或敲回车键,在弹出的面板中搜索关键字automake,找到并勾选compiler.automake.allow.when.app.running选项: 配置完成后,IntelliJ IDEA 可以热加载静态资源文件了.但是模板文件仍然还不能热加载. 2. 添加 Spring B

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

一.静态资源的存放路径 css,js,图片等静态资源存放在项目的路径必须为 二.html.jsp导入静态资源文件 html.jsp页面中的导入静态资源文件: js: css: 图片: 二.web.xml和SpringMVC配置文件中的配置 方法一: web.xml中的配置: SpringMVC配置文件中的配置: 方法二: web.xml中的配置: 与之对应的SpringMVC配置文件中不用特别配置 方法三: web.xml中的配置: 或者 与之对应的SpringMVC配置文件中不用再添加特殊配置

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

用maven搭建的java web项目,上传到git仓库后,当同事clone下来项目,部署到tomcat运行时,就报了如下错误,即启动web项目时,加载web.xml文件,找不到spring的监听器,控制台错误如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

java web 交流群 里面好多资源

群号:346293626 此群旨在为 java 从业人士提供一个开放的友好的交流.资源共享的平台: 资源内容: java 基础: javase 相关的 ppt,例子和相关文档... java 高级: servlet,三大框架,例子和相关文档... 数据库相关: mysql 资源.redis 服务器资源: linux相关的学习资料.python 资料... web 服务器资源: nginx 相关资源... javascript 资源: javascript 的各种常用组件介绍和例子... 还有其他

Java Web之网络通讯

一.head ,get,post请求方式主要区别 head只要求服务器返回HTTP响应消息的头字段 首先是"GET方式提交的数据最多只能是1024字节",因为GET是通过URL提交数据,那么GET可提交的数据量就跟URL的长度有直接关系 了.而实际上,URL不存在参数上限的问题,HTTP协议规范没有对URL长度进行限制.这个限制是特定的浏览器及服务器对它的限制.IE对URL长度的 限制是2083字节(2K+35).对于get方法浏览器将提交表单中的字段信息放置在请求头中,不适合大数据量

Java Web项目--显示一个静态页面

我们可以在Eclipse中新建一个Dynamic Web Project,然后在项目的WebContent目录下新建一个Html文件page1.html,其内容如下: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>page1</title> </head> <body> A Normal Html Page! <

磁盘 IO 和网络 IO 该如何评估、监控、性能定位和优化

生产中经常遇到一些IO延时长导致的系统吞吐量下降.响应时间慢等问题,例如交换机故障.网线老化导致的丢包重传:存储阵列条带宽度不足.缓存不足.QoS限制.RAID级别设置不当等引起的IO延时. 一.评估 IO 能力的前提 评估一个系统IO能力的前提是需要搞清楚这个系统的IO模型是怎么样的.那么IO模型是什么,为什么要提炼IO模型呢? (一).IO模型 在实际的业务处理过程中,一般来说IO比较混杂,比如说读写比例.IO尺寸等等,都是有波动的.所以我们提炼IO模型的时候,一般是针对某一个特定的场景来建