spring gzip 靜態壓縮優化


 HTTP 壓縮可以大大提高瀏覽網站的速度,它的原理是,在客戶端請求網頁后,從服務器端將網頁文件壓縮,再下載到客戶端,由客戶端的瀏覽器負責解壓縮並瀏覽。相對 於普通的瀏覽過程HTML ,CSS,Javascript , Text ,它可以節省40%左右的流量。更為重要的是,它可以對動態生成的,包括CGI、PHP , JSP , ASP , Servlet,SHTML等輸出的網頁也能進行壓縮,壓縮效率驚人。 
目前實現gzip壓縮有2種辦法: 

方法一、是有的容器(服務器)提供的功能,但這個局限於特定容器。比如 apache+tomcat 或者 resin-pro   
方法二、是 部署前手動 gzip 壓縮,配合 servlet 過濾器使用,這個能實現 gzip 功能,但是降低了靈活性。


方案一
1、TOMCAT配置GZIP壓縮:

tomcat5.5.x配置 
修改%TOMCAT_HOME%\conf \server.xml啟用支持gzip壓縮. 
添加下列屬性 
compression="on" 
compressionMinSize="2048" 
noCompressionUserAgents="gozilla, traviata" 
compressableMimeType="text/html,text/xml" 
TOMCAT配置說明 
1) compression="on" 打開壓縮功能 
2) compressionMinSize="2048" 啟用壓縮的輸出內容大小,這里面默認為2KB 
3) noCompressionUserAgents="gozilla, traviata" 對於以下的瀏覽器,不啟用壓縮 
4) compressableMimeType="text/html,text/xml" 壓縮類型 

Resin容器中配置GZIP壓縮方法 

http://localhost:8080/MyProj/pdf/0.jpg 可以打開一張圖片。用Httpwatch查看 
Accept-Encoding: gzip, deflate 
Sent    :    315 
Received    43106 

開始配置Resin 

我按照這樣的配置: 
<web-app id="/" root-directory="webapps/MyProj"> 
<filter filter-name="gzip" filter-class="com.caucho.filters.GzipFilter"> 
<init> 
<use-vary>true</use-vary> 
</init> 
</filter> 
<filter-mapping filter-name="gzip"> 
<url-pattern> 
<exclude-pattern>*.jpg</exclude-pattern> 
<include-pattern>/*</include-pattern> 
</url-pattern> 
</filter-mapping> 
</web-app> 

再測試發現不起作用!不清楚如何配置哦! 
我再看了一下資料上面有講說 需要resin的專業版即resin-pro 
現在再看下我的resin :Resin-3.2.1 (built Fri, 17 Oct 2008 04:11:01 PDT) 

果然是我的版本不一致導致的。重新從網上下載一下專業版的RESIN下來再試! 
以下是我再測試的過程: 
測試發現還是不行呀!我昏~~~ 不過感覺專業版與普通版在配置上面還是有點差別的 
待續未完! 

方案二: 
設置Content-Encoding 

Content-Encoding 文檔的編碼(Encode)方法。只有在解碼之后才可以得到Content-Type頭指定的內容類型。利用gzip壓縮文檔能夠顯著地減少HTML文檔 的下載時間。Java的GZIPOutputStream可以很方便地進行gzip壓縮,但只有Unix上的Netscape和Windows上的IE 4、IE 5才支持它。因此,Servlet應該通過查看Accept-Encoding頭(即request.getHeader("Accept- Encoding"))檢查瀏覽器是否支持gzip,為支持gzip的瀏覽器返回經gzip壓縮的HTML頁面,為其他瀏覽器返回普通頁面。 
壓縮流 
public void doGet(HttpServletRequest request, HttpServletResponse response) 
throws IOException, ServletException { 
OutputStream out = null; 
String encoding = request.getHeader("Accept-Encoding");   
if (encoding != null && encoding.indexOf("gzip") != -1){ 
request.setHeader("Content-Encoding" , "gzip");   
out = new GZIPOutputStream(request.getOutputStream()); 
}  
else if (encoding != null && encoding.indexOf("comdivss") != -1){ 
request.setHeader("Content-Encoding" , "comdivss");   
out = new ZIPOutputStream(request.getOutputStream()); 
}else{   
out = request.getOutputStream(); 



實例:
采用gzip servlet filter實現
從 HTTP/1.1 開始,客戶端就可以在請求頭中添加
Accept-Encoding: gzip,deflate      (可以從HTTP WATCH中查看發現確實支持)
來向請求的服務器表明自己支持 Gzip 壓縮的響應。Web 服務器則在響應頭中添加
Content-Encoding: gzip
來向客戶端表明響應體是經過 gzip 壓縮的。

程序代碼如下:
(在此非常感謝 http://tdcq.iteye.com/blog/453644 提供代碼)

具體代碼如下:
package sh.blog.util.web.filter; 
import java.io.IOException; 
import java.util.zip.GZIPOutputStream; 
import javax.servlet.ServletOutputStream; 
public class CompressedStream extends ServletOutputStream { 
private ServletOutputStream out; 
private GZIPOutputStream     gzip; 
/**
* 指定壓縮緩沖流
* @param 輸出流到壓縮
@throws IOException if an error occurs with the {@link GZIPOutputStream}.
*/ 
public CompressedStream(ServletOutputStream out) throws IOException { 
this.out = out; 
reset(); 


/** @see ServletOutputStream * */ 
public void close() throws IOException { 
gzip.close(); 


/** @see ServletOutputStream * */ 
public void flush() throws IOException { 
gzip.flush(); 


/** @see ServletOutputStream * */ 
public void write(byte[] b) throws IOException { 
write(b, 0, b.length); 


/** @see ServletOutputStream * */ 
public void write(byte[] b, int off, int len) throws IOException { 
gzip.write(b, off, len); 


/** @see ServletOutputStream * */ 
public void write(int b) throws IOException { 
gzip.write(b); 
}      

public void reset() throws IOException { 
gzip = new GZIPOutputStream(out); 






package sh.blog.util.web.filter;
import java.io.IOException;
import java.io.PrintWriter;    
import javax.servlet.ServletOutputStream;    
import javax.servlet.http.HttpServletResponse;    
import javax.servlet.http.HttpServletResponseWrapper;     

public class CompressionResponse extends HttpServletResponseWrapper{
protected HttpServletResponse response;    
private ServletOutputStream out;    
private CompressedStream compressedOut;  
private PrintWriter writer;    
protected int contentLength;    

public CompressionResponse(HttpServletResponse response) throws IOException {    
super(response);
this.response = response;    
compressedOut = new CompressedStream(response.getOutputStream()); 
}

public void setContentLength(int len) { 
contentLength = len;    
}

public ServletOutputStream getOutputStream() throws IOException {    
if (null == out) {    
if (null != writer) {  
throw new IllegalStateException("getWriter() has already been called on this response.");    
}
out = compressedOut;    
}
return out; 
}

public PrintWriter getWriter() throws IOException {    
if (null == writer) {    
if (null != out) {    
throw new IllegalStateException("getOutputStream() has already been called on this response.");
}
writer = new PrintWriter(compressedOut);  
}
return writer;    

}

public void flushBuffer() {    
try {    
if (writer != null) {
writer.flush();
}else if (out != null) {  
out.flush();    
}

}catch (IOException e) {  
e.printStackTrace();    
}
}

public void reset() {
super.reset();    
try {    
compressedOut.reset();    
}catch (IOException e) {  
throw new RuntimeException(e);    
}
}

public void resetBuffer() {    
super.resetBuffer();    
try {    
compressedOut.reset();    
}catch (IOException e) {  
throw new RuntimeException(e);
}
}

public void close() throws IOException {    
compressedOut.close();    
}



}



package sh.blog.util.web.filter;

import java.io.IOException;    
import java.util.Enumeration;    
import javax.servlet.Filter;    
import javax.servlet.FilterChain;    
import javax.servlet.FilterConfig;    
import javax.servlet.ServletException;    
import javax.servlet.ServletRequest;    
import javax.servlet.ServletResponse;    
import javax.servlet.http.HttpServletRequest;    
import javax.servlet.http.HttpServletResponse;    
import org.apache.commons.logging.Log;    
import org.apache.commons.logging.LogFactory;    

public class CompressionFilter implements Filter {    
protected Log log = LogFactory.getFactory().getInstance(this.getClass().getName());    

@SuppressWarnings("unchecked")    
public void doFilter(ServletRequest request, ServletResponse response,    
FilterChain chain) throws IOException, ServletException {    
boolean compress = false;    
if (request instanceof HttpServletRequest){    
HttpServletRequest httpRequest = (HttpServletRequest) request;  
Enumeration headers = httpRequest.getHeaders("Accept-Encoding");    
while (headers.hasMoreElements()){    
String value = (String) headers.nextElement();    
if (value.indexOf("gzip") != -1){    
compress = true;    
}    
}    
}    

if (compress){//如果瀏覽器支持則壓縮    
HttpServletResponse httpResponse = (HttpServletResponse) response; 
httpResponse.addHeader("Content-Encoding", "gzip");    
CompressionResponse compressionResponse= new CompressionResponse(httpResponse);    
chain.doFilter(request, compressionResponse);    
compressionResponse.close();    
}    
else{//如果瀏覽器不支持則不壓縮    
chain.doFilter(request, response);    
}    

}    

public void init(FilterConfig config) throws ServletException {    

}    

public void destroy(){    
}    

}    
一共有三個CLASS文件!實現GZIP壓縮輸出響應 

2.1 對圖片輸出做壓縮處理測試
建立目錄pdf里面存儲圖片
第一步:不配置過濾器用HTTP WATCHE發現
image/jpeg : 42891 bytes, 670 x 446 pixels


第二步:配置Web.xml配置過濾器
<filter>
<filter-name>gzip</filter-name>
<filter-class>sh.blog.util.web.filter.CompressionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>gzip</filter-name>
<url-pattern>/pdf/*</url-pattern>
</filter-mapping>

再用HTTP WATCH查看發現
image/jpeg : 42891 bytes, gzip compressed to 42712 bytes ( 0.417 % saving ), 670 x 446 pixels
實現了一次壓縮處理輸出!
PS:我再用png格式的圖片做過一次測試發現一次可以實現GZIP壓縮輸出
結論:通過上面的過濾器能夠實現對圖片的壓縮處理,提高響應速度!


2.2 對音樂的壓縮處理以MP3的輸出 為測試對象

建立目錄music里面存儲音樂
第一步:不配置過濾器發現
audio/mpeg : 9001 bytes of binary data

第二步:配置過濾器

<filter>
<filter-name>gzip</filter-name>
<filter-class>sh.blog.util.web.filter.CompressionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>gzip</filter-name>
<url-pattern>/music/*</url-pattern>    
</filter-mapping>

再次查看發現:
audio/mpeg : , gzip compressed to 0 bytes ( 0 % saving )
結論:上面的算法對音樂文件不起壓縮作用。感覺這種GZIP的算法應該是不同的格式算法不一樣


2.3 對JS文件壓縮輸出

第一步:不做壓縮
4864

第二步:配置壓縮
<filter>
<filter-name>gzip</filter-name>
<filter-class>sh.blog.util.web.filter.CompressionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>gzip</filter-name>
<url-pattern>/scripts/*.js</url-pattern>    
</filter-mapping>

輸出:
application/x-javascript : 4636 bytes, gzip compressed to 69 bytes ( 98.5 % saving )

查看發現JS的壓縮是相當高的了!
結論:將JS存入指定的目錄然后直接對此目錄做GZIP壓縮輸出。可以看到效果是顯著的!
通過做GZIP壓縮輸出之后可以減少網絡帶寬流量從而加快下載速度!



2.4 對CSS文件壓縮輸出

第一步:沒有壓縮輸出
text/css : 413 bytes

第二步:壓縮

配置:
<filter>
<filter-name>gzip</filter-name>
<filter-class>sh.blog.util.web.filter.CompressionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>gzip</filter-name>
<url-pattern>/scripts/*.js</url-pattern>    
<url-pattern>/style/*.css</url-pattern>
</filter-mapping>
結果:
text/css : 413 bytes, gzip compressed to 101 bytes ( 75.5 % saving )
結論:對CSS的壓縮效果也是非常明顯的哦!

2.5 對HTML頁面壓縮輸出

第一步:不壓縮
text/html : 2272 bytes

第二步;壓縮
<filter>
<filter-name>gzip</filter-name>
<filter-class>sh.blog.util.web.filter.CompressionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>gzip</filter-name>
<url-pattern>/scripts/*.js</url-pattern>    
<url-pattern>/style/*.css</url-pattern>
<url-pattern>*.html</url-pattern>
</filter-mapping>
結果:
text/html : 2272 bytes, gzip compressed to 240 bytes ( 89.4 % saving )

結論:對HTML的壓縮效果也是非常明顯的哦!

2.6 對JSP頁面的壓縮
第一步:未做壓縮
text/html; charset=iso-8859-1 : 1008 bytes

第二步:壓縮輸出
<filter>
<filter-name>gzip</filter-name>
<filter-class>sh.blog.util.web.filter.CompressionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>gzip</filter-name>
<url-pattern>/scripts/*.js</url-pattern>    
<url-pattern>/style/*.css</url-pattern>
<url-pattern>*.html</url-pattern>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>

結果:頁面 無輸出!

結論:
以上的算法可以應用於 圖片、HTML、CSS、JS的GZIP壓縮輸出。對於JSP頁面無效!

應用:

將來可以在站點中編寫此類過濾器,將頁面內容盡可能地做GZIP輸出提高下載的速度


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM