Spring压缩返回的数据提高响应速度

Spring压缩返回的数据提高响应速度:GZip

Zyyyyu 的个人博客
压缩过滤器

  • 功能:对于返回给客户端的数据进行gzip压缩,提高响应速度
  • 实现说明:

要对response对象的输出数据进行gzip压缩,首先得拿到后面servlet(controller)进行业务处理后往response对象里写入的数据
可以通过重写response对象,修改该对象内部的输出流,使该流写出数据时写出到给定的字节数组缓冲流当中,
并在重写后的response对象内部提供一个获取该字节数组缓冲流的方法,这样就可以截获响应数据
然后就可以对截获的响应数据通过Gzip输出流进行压缩输出即可;
因为响应数据是gzip压缩格式,不是普通的文本格式所以需要通过response对象(响应头)告知浏览器响应的数据类型

文件1


@Slf4j
public class GzipFilter implements Filter {

    private final String GZIP = "gzip";

    public void destroy() {
        log.info("GzipFilter destroy");
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        log.info("GzipFilter start");
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        String acceptEncoding = request.getHeader(HttpHeaders.ACCEPT_ENCODING);
        //searching for 'gzip' in ACCEPT_ENCODING header
        if( acceptEncoding != null && acceptEncoding.indexOf(GZIP) >= 0){
            GzipResponseWrapper gzipResponseWrapper = new GzipResponseWrapper(response);
            //pass the customized response object to controller to capture the output data
            chain.doFilter(request, gzipResponseWrapper);
            //get captured data
            byte[] data = gzipResponseWrapper.getOutputData();
            log.info("截获到数据:" + data.length + " bytes");
            //get gzip data
            ByteArrayOutputStream gzipBuffer = new ByteArrayOutputStream();
            GZIPOutputStream gzipOut = new GZIPOutputStream(gzipBuffer);
            gzipOut.write(data);
            gzipOut.flush();
            gzipOut.close();
            byte[] gzipData = gzipBuffer.toByteArray();
            log.info("压缩后数据:" + gzipData.length + " bytes");
            //set response header and output
            response.setHeader(HttpHeaders.CONTENT_ENCODING, GZIP);
            response.getOutputStream().write(gzipData);
            response.getOutputStream().flush();
        }else{
            chain.doFilter(req, resp);
        }
    }

    public void init(FilterConfig config) throws ServletException {
        log.info("GzipFilter init");
    }

}

文件2


@Slf4j
public class GzipResponseWrapper extends HttpServletResponseWrapper {

    /**
     * 字节数组缓冲流,用来保存截获到的输出数据
     */
    private ByteArrayOutputStream buffer;

    /**
     * 重新定义servlet输出流,改变输出目的地将响应内容输出到给定的字节数组缓冲流中
     */
    private CustomServletOutputStream servletOutputStream;

    /**
     * 同上
     */
    private PrintWriter writer;

    public GzipResponseWrapper(HttpServletResponse response) {
        super(response);
        //original HttpServletResponse object
        buffer = new ByteArrayOutputStream();
        servletOutputStream = new CustomServletOutputStream(buffer);
        try {
            writer = new PrintWriter(new OutputStreamWriter(buffer, response.getCharacterEncoding()), true);
        } catch (UnsupportedEncodingException e) {
            log.error("GZipHttpServletResponse", e);
        }
    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return servletOutputStream;
    }

    @Override
    public PrintWriter getWriter() throws IOException {
        return writer;
    }

    @Override
    public void flushBuffer() throws IOException {
        if (servletOutputStream != null) {
            servletOutputStream.flush();
        }
        if (writer != null) {
            writer.flush();
        }
    }

    /**
     * 向外部提供一个获取截获数据的方法
     * @return 从response输出流中截获的响应数据
     */
    public byte[] getOutputData() throws IOException {
        flushBuffer();
        return buffer.toByteArray();
    }

    private static class CustomServletOutputStream extends ServletOutputStream {

        /**
         * 字节数组缓冲流,用来保存截获到的输出数据
         */
        private ByteArrayOutputStream buffer;

        public CustomServletOutputStream(ByteArrayOutputStream buffer) {
            this.buffer = buffer;
        }

        @Override
        public boolean isReady() {
            return true;
        }

        @Override
        public void setWriteListener(WriteListener listener) {
        }

        /**
         * 重写输出流相关的方法
         * 将输出数据写出到给定的ByteArrayOutputStream缓冲流中保存起来
         * @param b 输出的数据
         * @throws IOException
         */
        @Override
        public void write(int b) throws IOException {
            buffer.write(b);
        }
    }
}

文件3


/**
 * 注册filter
 */
@Configuration
public class FilterRegistration {

    @Bean
    public FilterRegistrationBean<GzipFilter> gzipFilterRegistrationBean() {
        FilterRegistrationBean<GzipFilter> registration = new FilterRegistrationBean<>();
        //Filter可以new,也可以使用依赖注入Bean
        registration.setFilter(new GzipFilter());
        //过滤器名称
        registration.setName("gzipFilter");
        //拦截路径
        registration.addUrlPatterns("/*");
        //设置顺序
        registration.setOrder(1);
        return registration;
    }
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值