壓縮響應問題---HttpServletResponse物件增強
阿新 • • 發佈:2018-12-27
在向瀏覽器傳送響應內容時,可以對響應內容進行壓縮,將壓縮後的內容傳送到瀏覽器,同時通知瀏覽器發過來的內容是使用何種演算法進行壓縮的,瀏覽器再顯示時,將以此中方法進行解碼。這樣可以節省傳輸頻寬,加快響應速度。這裡可以利用Filter來實現全站的響應內容壓縮問題。但是HttpServletResponse物件本身不具有壓縮響應內容的功能,因此可以對其進行功能增強。
HttpServletResponseWrapper是對HttpServletResonse的預設包裝類,MyCompressResponse是繼承了HttpServletResponseWrapper類的包裝類;由於response向瀏覽器上輸出顯示內容有兩個方法,一個是同通過getOutputStream獲取流物件,呼叫其write方法將資料寫入outputStream流中。另一種方法是通過獲取getWriter來獲取一個PrintWriter的物件,通過其write方法想瀏覽器寫入一個字串,一個是基於bit流的,一個是基於字元流的。但是response本身這兩中方法都是直接向瀏覽器輸出響應內容,本沒有對其進行壓縮,因此需要對其進行增強。其思想是增強後的方法,將會先把響應內容輸出到一個快取內,對快取內的內容進行壓縮處理,能夠後將壓縮後的內容輸出到瀏覽器中,同時通知瀏覽器,接受到的內容是通過什麼演算法壓縮的及內容的大小,這時,瀏覽器將會根據此來顯示響應內容。下面是增強的MyCompressResponse,具體如下:
Filter:import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import javax.servlet.ServletOutputStream; import javax.servlet.ServletResponse; import javax.servlet.ServletResponseWrapper; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; public class MyCompressResponse extends HttpServletResponseWrapper { private HttpServletResponse response; //接受一個response物件,將對其進行增強 private ByteArrayOutputStream bout = new ByteArrayOutputStream(); //快取流,所有響應內容將會被輸出到此 private PrintWriter pw; public MyCompressResponse(HttpServletResponse response) { super(response); // TODO Auto-generated constructor stub this.response = response; } /* (non-Javadoc) * @see javax.servlet.ServletResponseWrapper#getOutputStream() */ @Override public ServletOutputStream getOutputStream() throws IOException { // TODO Auto-generated method stub return new MyOutputStream(bout); //重寫getOutputStream方法 } @Override public PrintWriter getWriter() throws IOException { // TODO Auto-generated method stub pw = new MyPrintWriter(bout, super.getCharacterEncoding()); //重寫getWriter方法,同時對其write方法進行增強,write方法可以指定編碼方式 return pw; } public byte[] getBuffer(){ if(pw!=null){ pw.close();//將資料輸出到bout流中 } if(bout!=null){ return bout.toByteArray();//將快取返回 } return null; } } class MyOutputStream extends ServletOutputStream{ private ByteArrayOutputStream bout; @Override public void write(int b) throws IOException { // TODO Auto-generated method stub bout.write(b); //將響應內容寫到bout快取流中 } public MyOutputStream(ByteArrayOutputStream bout){ this.bout = bout; } } class MyPrintWriter extends PrintWriter{ private ByteArrayOutputStream bout; private String charset; public MyPrintWriter(ByteArrayOutputStream bout, String charset) { super(bout); // TODO Auto-generated constructor stub this.bout = bout; //建立一個PrintWriter,指定字元編碼方式 this.charset = charset; } /* (non-Javadoc) * @see java.io.PrintWriter#write(java.lang.String) */ @Override public void write(String s) { // TODO Auto-generated method stub try { bout.write(s.getBytes(charset)); //根據指定的編碼方式,將響應內容寫入到bout快取 } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
public class MyCompressFilter implements Filter{ private FilterConfig filterConfig; @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub HttpServletRequest request = (HttpServletRequest)req; HttpServletResponse response = (HttpServletResponse)resp; MyCompressResponse gzipResp = new MyCompressResponse(response); //使用gzipResp進行放行 chain.doFilter(request, gzipResp); byte[] out = gzipResp.getBuffer(); //獲取快取內容 ByteArrayOutputStream bout = new ByteArrayOutputStream(); GZIPOutputStream gout = new GZIPOutputStream(bout); gout.write(out); gout.close(); //將快取內容寫入到使用GZIP方式壓縮的流中 byte[] gzip = bout.toByteArray(); System.out.println("length:"+out.length);//通知瀏覽器響應內容的壓縮方式及內容長度 response.setHeader("content-encoding", filterConfig.getInitParameter("encoding")); response.setContentLength(gzip.length); response.getOutputStream().write(gzip); //使用response將壓縮後的內容寫到瀏覽器中 } @Override public void init(FilterConfig filterConfig) throws ServletException { // TODO Auto-generated method stub this.filterConfig = filterConfig; } }