原创文章,转载请注明
gzip为一种压缩技术,在网络http传输中得到应用。gzip需要web容器,浏览器的支持。
看一下效果
压缩前:
压缩后:
这里的时间不需要纠结,开发环境在本机,这里的性能损耗主要在cpu上,也就是压缩时消耗的cpu,而且本机还跑了其他东西,不同时刻的环境不太一样。
tomcat中使用gzip需要进行配置,在server.xml中,在Connector标签中加入如下属性
comPRession="on"compressionMinSize="2048"noCompressionUserAgents="gozilla,traviata"compressableMimeType="text/html,text/CSS.text/javascript" compression:指定是否开启压缩compressionMinSize:表示小于该值进行压缩,单位为Byte
noCompressionUserAgents:表示不进行压缩的浏览器
compressableMimeType:表示哪些格式的文件需要被压缩
注意:图片不要进行压缩,因为图片完全可以在项目开发中使用压缩后的图片。这样避免了压缩对于CPU的消耗
2、代码
除了进行tomcat配置之外,还需要对请求写一个filter进行压缩。
2.1、GZIPOutputStream
主要是通过该类进行压缩,它由java.util.zip包提供
2.2、ServletResponse、HttpServletResponse、ServletResponseWrapper、HttpServletResponseWrapper、WrappedOutputStream
需要继承HttpServletResponseWrapper,复写其中的getWriter,getOutputStream方法从而获得响应数据,然后就可以调用gzipOutputStream进行压缩。
这里顺道说一下这几个类的关系
ServletResponse为最基本的接口,表示response。
HttpServletResponse扩展了ServletRespones,表示http协议下的response
ServletResponseWrapper实现了ServletResponse
HttpServletResponseWrapper实现了HttpServletResponse
所以我们平时用的HttpServletResponse默认的实现为HttpServletResponseWrapper,struts2似乎在这之上又包装了一层。
WrappedOutputStream:在我们调用getOutputStream方法时,会通过该接口的write方法输出byte
2.3思路
思路很清晰了,通过继承HttpServletResponseWrapper重写getWriter,getOutputStream获得响应数据,在stream的输出时,需要通过WrappedOutputStream的write方法输出byte。最后把输出的byte通过gzipOutputStream进行压缩
来看一个实现代码
package com.zs.vehicle.filter;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.util.zip.GZIPOutputStream;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletOutputStream;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.zs.vehicle.utils.Wrapper;public class GZipFilter implements Filter{ @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub HttpServletResponse resp=(HttpServletResponse) response; HttpServletRequest req=(HttpServletRequest) request; if(isGZipEncoding(req)){ Wrapper wrapper=new Wrapper(resp); chain.doFilter(request, wrapper); byte[] gzipData=gzip(wrapper.getResponseData()); resp.addHeader("Content-Encoding", "gzip"); resp.setContentLength(gzipData.length); ServletOutputStream output=response.getOutputStream(); output.write(gzipData); output.flush(); }else{ chain.doFilter(request, response); } } @Override public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub } private static boolean isGZipEncoding(HttpServletRequest request){ boolean flag=false; String encoding=request.getHeader("Accept-Encoding"); if(encoding.indexOf("gzip")!=-1){ flag=true; } return flag; } private byte[] gzip(byte[] data){ ByteArrayOutputStream byteOutput=new ByteArrayOutputStream(10240); GZIPOutputStream output=null; try{ output=new GZIPOutputStream(byteOutput); output.write(data); }catch(Exception e){ e.printStackTrace(); }finally{ try{ output.close(); }catch(Exception e){ e.printStackTrace(); } } return byteOutput.toByteArray(); } }package com.zs.vehicle.utils;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.OutputStreamWriter;import java.io.PrintWriter;import javax.servlet.ServletOutputStream;import javax.servlet.WriteListener;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpServletResponseWrapper;public class Wrapper extends HttpServletResponseWrapper{ public static final int OT_NONE=0; public static final int OT_WRITER=1; public static final int OT_STREAM=2; private int outputType=OT_NONE; private ServletOutputStream output=null; private PrintWriter writer=null; private ByteArrayOutputStream buffer=null; public Wrapper(HttpServletResponse response) { super(response); buffer=new ByteArrayOutputStream(); } @Override public PrintWriter getWriter() throws IOException{ if(outputType==OT_STREAM) throw new IllegalStateException(); else if(outputType==OT_WRITER) return writer; else{ outputType=OT_WRITER; writer=new PrintWriter(new OutputStreamWriter(buffer,getCharacterEncoding())); return writer; } } @Override public ServletOutputStream getOutputStream() throws IOException{ if(outputType==OT_WRITER) throw new IllegalStateException(); else if(outputType==OT_STREAM) return output; else{ outputType=OT_STREAM; output=new WrappedOutputStream(buffer); return output; } } @Override public void flushBuffer() throws IOException{ if(outputType==OT_WRITER) writer.flush(); if(outputType==OT_STREAM) output.flush(); } @Override public void reset(){ outputType=OT_NONE; buffer.reset(); } public byte[] getResponseData() throws IOException{ flushBuffer(); return buffer.toByteArray(); } class WrappedOutputStream extends ServletOutputStream{ private ByteArrayOutputStream buffer; public WrappedOutputStream(ByteArrayOutputStream buffer){ this.buffer=buffer; } @Override public void write(int b) throws IOException { buffer.write(b); } public byte[] toByteArray(){ return buffer.toByteArray(); } @Override public boolean isReady() { // TODO Auto-generated method stub return true; } @Override public void setWriteListener(WriteListener listener) { // TODO Auto-generated method stub } } }3、spring-boot
对于spring-boot来说,由于其内嵌了web容器,那么它的行为是怎样的呢。
spring-boot的web容器是默认开启了gzip压缩的,而且不会对图片进行压缩。
新闻热点
疑难解答