tomcat gzip 網頁壓縮技術
阿新 • • 發佈:2019-01-10
gzip是http協議中使用的一種加密演算法,客戶端向web伺服器端發出了請求後,通常情況下伺服器端會將頁面檔案和其他資源,返回到客戶端,客戶端載入後渲染呈現,這種情況檔案一般都比較大,如果開啟Gzip ,那麼伺服器端響應後,會將頁面,JS,CSS等文字檔案或者其他檔案通過高壓縮演算法將其壓縮,然後傳輸到客戶端,由客戶端的瀏覽器負責解壓縮與呈現。通常能節省40%以上的流量(一般都有60%左右),一些PHP,JSP檔案也能夠進行壓縮。
1.Tomcat 直接開啟Gzip
開啟Tomcat 目錄下的conf下的server.xml,並找到如下資訊:
Xml程式碼
把它們加入到你配置的<Connector port="80" .../>中去。如果要壓縮css 和 js,加入compressableMimeType="text/html,text/xml,text/css,text/javascript"。還要壓縮圖片,加入compressableMimeType="text/html,text/xml,text/css,text/javascript,image/gif,image/jpg"。
開啟後重啟Tomcat ,通過瀏覽器檢視headers資訊就能看到是否開啟。
2.使用filter,在程式碼級別完成web應用的gzip壓縮的開啟。
(1).CachedResponseWrapper類
實現定製輸出的關鍵是對HttpServletResponse 進行包裝,截獲所有的輸出,等到過濾器鏈處理完畢後,再對截獲的輸出進行處理,並寫入到真正的HttpServletResponse 物件中。JavaEE 框架已經定義了一個HttpServletResponseWrapper 類使得包裝HttpServletResponse 更加容易。我們擴充套件這個HttpServletResponseWrapper,截獲所有的輸出,並儲存到ByteArrayOutputStream 中。
定製的包裝響應能方便地從幫助類 HttpServletResponseWrapper 中匯出。這一類粗略地執行許多方法,允許我們簡單地覆蓋 getOutputStream() 方法以及 getWriter() 方法,提供了定製輸出流的例項。
HttpServletResponseWrapper這個類的使用包括以下五個步驟:
1)建立一個響應包裝器。擴充套件javax.servlet.http.HttpServletResponseWrapper。
2)提供一個快取輸出的PrintWriter。過載getWriter方法,返回一個儲存傳送給它的所有東西的PrintWriter,並把結果存進一個可以稍後訪問的欄位中。
3)傳遞該包裝器給doFilter。此呼叫是合法的,因為HttpServletResponseWrapper實現HttpServletResponse。
4)提取和修改輸出。在呼叫FilterChain的doFilter方法後,原資源的輸出只要利用步驟2中提供的機制就可以得到。只要對你的應用適合,就可以修改或替換它。
5)傳送修改過的輸出到客戶機。因為原資源不再發送輸出到客戶機(這些輸出已經存放到你的響應包裝器中了),所以必須傳送這些輸出。這樣,你的過濾器需要從原響應物件中獲得PrintWriter或OutputStream,並傳遞修改過的輸出到該流中。
Java程式碼
(2).GZipFilter類
Java程式碼
(3).GZipUtil類
Java程式碼
(4).在web.xml中配置 GZipFilter
Xml程式碼
1.Tomcat 直接開啟Gzip
開啟Tomcat 目錄下的conf下的server.xml,並找到如下資訊:
Xml程式碼
- <!-- Note : To use gzip compression you could set the following properties :
- compression="on"
- compressionMinSize="2048"
- noCompressionUserAgents="gozilla, traviata"
- compressableMimeType="text/html,text/xml"
- -->
<!-- Note : To use gzip compression you could set the following properties : compression="on" compressionMinSize="2048" noCompressionUserAgents="gozilla, traviata" compressableMimeType="text/html,text/xml" -->
把它們加入到你配置的<Connector port="80" .../>中去。如果要壓縮css 和 js,加入compressableMimeType="text/html,text/xml,text/css,text/javascript"。還要壓縮圖片,加入compressableMimeType="text/html,text/xml,text/css,text/javascript,image/gif,image/jpg"。
開啟後重啟Tomcat ,通過瀏覽器檢視headers資訊就能看到是否開啟。
2.使用filter,在程式碼級別完成web應用的gzip壓縮的開啟。
(1).CachedResponseWrapper類
實現定製輸出的關鍵是對HttpServletResponse 進行包裝,截獲所有的輸出,等到過濾器鏈處理完畢後,再對截獲的輸出進行處理,並寫入到真正的HttpServletResponse 物件中。JavaEE 框架已經定義了一個HttpServletResponseWrapper 類使得包裝HttpServletResponse 更加容易。我們擴充套件這個HttpServletResponseWrapper,截獲所有的輸出,並儲存到ByteArrayOutputStream 中。
定製的包裝響應能方便地從幫助類 HttpServletResponseWrapper 中匯出。這一類粗略地執行許多方法,允許我們簡單地覆蓋 getOutputStream() 方法以及 getWriter() 方法,提供了定製輸出流的例項。
HttpServletResponseWrapper這個類的使用包括以下五個步驟:
1)建立一個響應包裝器。擴充套件javax.servlet.http.HttpServletResponseWrapper。
2)提供一個快取輸出的PrintWriter。過載getWriter方法,返回一個儲存傳送給它的所有東西的PrintWriter,並把結果存進一個可以稍後訪問的欄位中。
3)傳遞該包裝器給doFilter。此呼叫是合法的,因為HttpServletResponseWrapper實現HttpServletResponse。
4)提取和修改輸出。在呼叫FilterChain的doFilter方法後,原資源的輸出只要利用步驟2中提供的機制就可以得到。只要對你的應用適合,就可以修改或替換它。
5)傳送修改過的輸出到客戶機。因為原資源不再發送輸出到客戶機(這些輸出已經存放到你的響應包裝器中了),所以必須傳送這些輸出。這樣,你的過濾器需要從原響應物件中獲得PrintWriter或OutputStream,並傳遞修改過的輸出到該流中。
Java程式碼
- class
- public static final int OUTPUT_NONE = 0;
- public static final int OUTPUT_WRITER = 1;
- public static final int OUTPUT_STREAM = 2;
- private int outputType = OUTPUT_NONE;
- private int status = SC_OK;
- private ServletOutputStream output = null;
- private
- private ByteArrayOutputStream buffer = null;
- public CachedResponseWrapper(HttpServletResponse resp) throws IOException {
- super(resp);
- buffer = new ByteArrayOutputStream();
- }
- public int getStatus() {
- return status;
- }
- public void setStatus(int status) {
- super.setStatus(status);
- this.status = status;
- }
- public void setStatus(int status, String string) {
- super.setStatus(status, string);
- this.status = status;
- }
- public void sendError(int status, String string) throws IOException {
- super.sendError(status, string);
- this.status = status;
- }
- public void sendError(int status) throws IOException {
- super.sendError(status);
- this.status = status;
- }
- public void sendRedirect(String location) throws IOException {
- super.sendRedirect(location);
- this.status = SC_MOVED_TEMPORARILY;
- }
- public PrintWriter getWriter() throws IOException {
- if (outputType == OUTPUT_STREAM)
- throw new IllegalStateException();
- else if (outputType == OUTPUT_WRITER)
- return writer;
- else {
- outputType = OUTPUT_WRITER;
- writer = new PrintWriter(new OutputStreamWriter(buffer,
- getCharacterEncoding()));
- return writer;
- }
- }
- public ServletOutputStream getOutputStream() throws IOException {
- if (outputType == OUTPUT_WRITER)
- throw new IllegalStateException();
- else if (outputType == OUTPUT_STREAM)
- return output;
- else {
- outputType = OUTPUT_STREAM;
- output = new WrappedOutputStream(buffer);
- return output;
- }
- }
- public void flushBuffer() throws IOException {
- if (outputType == OUTPUT_WRITER)
- writer.flush();
- if (outputType == OUTPUT_STREAM)
- output.flush();
- }
- public void reset() {
- outputType = OUTPUT_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;
- }
- public void write(int b) throws IOException {
- buffer.write(b);
- }
- public byte[] toByteArray() {
- return buffer.toByteArray();
- }
- }
- }
class CachedResponseWrapper extends HttpServletResponseWrapper { public static final int OUTPUT_NONE = 0; public static final int OUTPUT_WRITER = 1; public static final int OUTPUT_STREAM = 2; private int outputType = OUTPUT_NONE; private int status = SC_OK; private ServletOutputStream output = null; private PrintWriter writer = null; private ByteArrayOutputStream buffer = null; public CachedResponseWrapper(HttpServletResponse resp) throws IOException { super(resp); buffer = new ByteArrayOutputStream(); } public int getStatus() { return status; } public void setStatus(int status) { super.setStatus(status); this.status = status; } public void setStatus(int status, String string) { super.setStatus(status, string); this.status = status; } public void sendError(int status, String string) throws IOException { super.sendError(status, string); this.status = status; } public void sendError(int status) throws IOException { super.sendError(status); this.status = status; } public void sendRedirect(String location) throws IOException { super.sendRedirect(location); this.status = SC_MOVED_TEMPORARILY; } public PrintWriter getWriter() throws IOException { if (outputType == OUTPUT_STREAM) throw new IllegalStateException(); else if (outputType == OUTPUT_WRITER) return writer; else { outputType = OUTPUT_WRITER; writer = new PrintWriter(new OutputStreamWriter(buffer, getCharacterEncoding())); return writer; } } public ServletOutputStream getOutputStream() throws IOException { if (outputType == OUTPUT_WRITER) throw new IllegalStateException(); else if (outputType == OUTPUT_STREAM) return output; else { outputType = OUTPUT_STREAM; output = new WrappedOutputStream(buffer); return output; } } public void flushBuffer() throws IOException { if (outputType == OUTPUT_WRITER) writer.flush(); if (outputType == OUTPUT_STREAM) output.flush(); } public void reset() { outputType = OUTPUT_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; } public void write(int b) throws IOException { buffer.write(b); } public byte[] toByteArray() { return buffer.toByteArray(); } } }
(2).GZipFilter類
Java程式碼
- public class GZipFilter implements Filter {
- public void init(FilterConfig arg0) throws ServletException {
- }
- public void doFilter(ServletRequest request, ServletResponse response,
- FilterChain chain) throws IOException, ServletException {
- HttpServletResponse httpResponse = (HttpServletResponse) response;
- CachedResponseWrapper wrapper = new CachedResponseWrapper(httpResponse);
- // 寫入wrapper:
- chain.doFilter(request, wrapper);
- // 對響應進行處理,這裡是進行GZip壓縮:
- byte[] data = GZipUtil.gzip(wrapper.getResponseData());
- httpResponse.setHeader("Content-Encoding", "gzip");
- httpResponse.setContentLength(data.length);
- ServletOutputStream output = response.getOutputStream();
- output.write(data);
- output.flush();
- }
- public void destroy() {
- }
- }
public class GZipFilter implements Filter { public void init(FilterConfig arg0) throws ServletException { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse httpResponse = (HttpServletResponse) response; CachedResponseWrapper wrapper = new CachedResponseWrapper(httpResponse); // 寫入wrapper: chain.doFilter(request, wrapper); // 對響應進行處理,這裡是進行GZip壓縮: byte[] data = GZipUtil.gzip(wrapper.getResponseData()); httpResponse.setHeader("Content-Encoding", "gzip"); httpResponse.setContentLength(data.length); ServletOutputStream output = response.getOutputStream(); output.write(data); output.flush(); } public void destroy() { } }
(3).GZipUtil類
Java程式碼
- public final class GZipUtil {
- public static byte[] gzip(byte[] data) {
- ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(10240);
- GZIPOutputStream output = null;
- try {
- output = new GZIPOutputStream(byteOutput);
- output.write(data);
- } catch (IOException e) {
- throw new RuntimeException("G-Zip failed.", e);
- } finally {
- if (output != null) {
- try {
- output.close();
- } catch (IOException e) {
- }
- }
- }
- return byteOutput.toByteArray();
- }
- }
public final class GZipUtil { public static byte[] gzip(byte[] data) { ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(10240); GZIPOutputStream output = null; try { output = new GZIPOutputStream(byteOutput); output.write(data); } catch (IOException e) { throw new RuntimeException("G-Zip failed.", e); } finally { if (output != null) { try { output.close(); } catch (IOException e) { } } } return byteOutput.toByteArray(); } }
(4).在web.xml中配置 GZipFilter
Xml程式碼
- <filter>
- <filter-name>GZipFilter</filter-name>
- <filter-class>com.logcd.filter.GZipFilter</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>GZipFilter</filter-name>
- <url-pattern>*.html</url-pattern>
- </filter-mapping>