如何利用HTTP緩存提升網頁性能

網站的性能(Performance)要考慮兩方面,一方面是在Server端的運行效率,另外一方面是在Client端感覺到的效率。不要覺得 Server端效率高這個網站或者服務給用戶的體驗就是高效的,若是不考慮影響Client Performance的因素,Server端跑得再快用戶也可能感受慢得和牛同樣。html

Yahoo的哥們作的研究真不是蓋的,他們還寫了本書《High Performance Web Sites》詳細介紹若是提升Client Performance。公司內部也有一個Team作這方面的事情,聽過他們的培訓,和Yahoo說的差很少,所謂英雄所見略同。前端

給靜態資源(HTML文件,圖片文件等)的Repsone加上Expires/Cache-Control Header是頗有效的一招。若是HTTP Response中有Expires這樣的Header的話,瀏覽器會Cache這個資源,理想情況下(注意,只是理想情況),在Expire Date以前,不會再發HTTP請求給Server要這個資源,不過Expires的值只能是一個固定日期,好比「Thu 27 Nov 2008 07:00:00 GMT」,不能是一個相似「從如今開始以後10年」這樣一個隨機浮動的值,若是要這樣的效果,能夠用Cache-Control這樣的Header,若是 HTTP Resposne中有這樣的Header:「Cache-Control: max-age = 100」,表示這個資源在cache中的最大壽命是100秒。通常說來這種靜態文件永遠不該該過時,若是真的要給這個Cache加上一個期限,那我但願是 ——一萬年,「Cache-Control: max-age = 315360000000」;node

其實就應該給Expires設一個永遠不會過時的時間,好比你如今有一個文件叫logo.gif,須要用一個新的logo的時候,你不要去覆蓋原來 的文件,而把新的logo存成logo_v2.gif,讓相關網頁引用新的logo_v2.gif,這樣可讓新老網頁同時工做,實在犯不上爲了節省存儲 空間覆蓋原有文件。算法

對Apache服務器,使用mod_expires,在httpd.conf或者.htaccess中加上瀏覽器

<FilesMatch "\\.(ico|gif|jpg|html)$">
ExpiresDefault "access plus 10 years"
</FileMatch>

對於IIS 6(IIS 7還不清楚),經過IIS Manager能夠經過GUI添加Expires/Cache-Control,經過命令行修改就麻煩一點了。 服務器

首先要到IIS的AdminScripts目錄下去找到adsutil.vbs文件。網絡

cd C:\Inetpub\AdminScripts ide

好比咱們要給根目錄下的imags目錄添加Expires/Cache-Control,先要在metabase中給它加一個節點性能

cscript adsutil.vbs create W3SVC/1/root/images "IisWebVirtualDir"網站

若是但願訪問images目錄下的文件得到Cache-Control: max-age=60,就這樣

csript adsutil.vbs set W3SVC/1/root/images/HttpExpires "D, 0x3c"

若是但願訪問images目錄下的文件得到「Expires: Thu 27 Nov 2008 07:00:00 GMT」,就這樣

csript adsutil.vbs set W3SVC/1/root/images/HttpExpires "S, Thu 27 Nov 2008 07:00:00 GMT"

還有,同一個HTTP Response中能夠同時有Expires和Cache-Control,可是Cache-Control權限比Expires大,會override它的。

HTTP的Response中還會有另一個Header叫Last-Modified,好比「Last- Modified: Thu, 06 Apr 2006 21:17:12 GMT」,瀏覽器訪問一個URI獲得這樣的Resposne以後,就知道這個資源最後一次的修改時間,下次須要再次得到這個資源的時候,會發一個 Request給Server,不過這個Request中有一條「If-Unmodified-Since: Thu, 06 Apr 2006 21:17:12 GMT」,若是在Server端在這個日期以後對這個資源進行了修改,就會照常返回這個資源給Client端,可是若是沒有修改,就會返回一個304 (Not Modified) Response而不返回資源,告訴Client端:「這個資源從上次給你之來歷來沒改過,你放心用你Cache中的好了。」 一個304 Response比一個靜態資源一般小多了,這樣就節省了網絡帶寬。

讓咱們回過頭來比較一下Expires和Last-Modified這兩個東西,彷佛Last-Modified比不上Expires,由於雖然它 可以節省一點帶寬,可是仍是逃不掉髮一個HTTP請求出去,而Expires卻使得瀏覽器乾脆連HTTP請求都不用發,豈不痛快!那還要Last- Modified這個物體幹什麼?理想情況的確是這樣,不過當用戶在IE或者Firefox裏面按F5或者點擊Refresh按鈕的時候(不是在URL欄 裏從新輸入一遍URL而後回車),就算對於有Expires的URI,同樣也會發一個HTTP請求出去,因此,Last-Modified仍是要用的,而 且要和Expires一塊兒用。

除了Last-Modified,HTTP Response中還可能有另一個Header: ETag, 使得Server上的靜態資源有點「版本控制」的味道;假如HTTP Response中包含「ETag: "abcdefg1234:0001"」,等於告訴Client端,你拿到的這個版本的資源有個ID,叫作abcdefg1234:0001,下次須要發 Request索要同一個URI的時候,在Request裏面加一條「If-None-Match: "abcdefg1234:0001"」,好,Server端作了一些修改,下次這個Client再來了一個請求,可是這時候資源已經改了,因此返回這個 新資源,還有新的tag 「ETag: "abcdefg4567:0001"」(這個etag我是胡寫的),這樣,Client端等於Cache了兩份,在須要索要這個資源的時候,能夠包含這 樣的Header: 「If-None-Match: "abcdefg1234:0001" "abcdefg4567:0001"」,這樣,即便Server端頭腦發熱,把這個資源Roll back回原來的版本,依然會返回304 (Not Modified) Response,由於它知道Client端Cache着之前的版本呢,這點功能是Last-Modifed/If-Not-Modified無法作到 的。

不過ETag/If-None-Match這點功能實在是個雞肋,首先,Server端的資源不大可能Roll Back,更重要的是,有可能形成Client Performance降低。對於只有一個Server的網站,沒什麼問題,可是如今稍微上點規模的網站都須要Scale Out,也就是說須要前端一個Load Balancer,後面接多臺Server來處理請求,俗稱Cluster,既然是Cluster,那麼每一個請求到底返回什麼結果應該和分配到哪一個 Server無關,不過這個ETag可能就壞事了。假如用戶的第一次請求分配給Server A,返回「ETag: "abcdefg1234:0001"」,可是第二次請求分配給了Server B,Server B上這個資源和Server A上的如出一轍,可是計算出這個資源的ETag是"abcdefg1234:0002",這下麻煩了,雖然內容同樣,可是ETag不匹配,仍是浪費了帶寬 把資源發送了一遍,冤枉啊!而事實上,不一樣Server上的ETag頗有可能不一樣,對於Apache,ETag的計算考慮了inode,對於 IIS,ETag考慮了metabase的修改版本,要保證不一樣server上的這些信息一致,有點小難。不過不是有Last-Modified/If- Not-Modified嗎?Server端看到If-Modified-Since,對照一下時間對得上,無論If-None-Match,能夠直接發 回304(Not Modified)呀,很不幸,RFC2616對這種狀況作了規定,若是既有If-None-Match又有If-Modified-Since,除非二者不衝突,否則不會返回304。

因此說ETag就是一個害人精,按照Yahoo的建議,別費勁想辦法同步不一樣Server上的ETag了,乾脆就把ETag刪除得了(缺 省,Apache和IIS都是有ETag的),我Sniff了一下Yahoo的若干網頁返回HTTP Response,的確沒有ETag,人家的確是知行合一;

對於Apache,在httpd.conf或者.htaccess中加一行就搞定了:

FileETag none

對於IIS 6,可就有點費勁了,首先,彷佛沒有辦法經過Config來把ETag去掉,查了不少資料,問了不少人,彷佛可以去掉ETag的辦法只有寫一個ISAPI Filter來弄,Sniff了一下Microsoft的幾個網頁的結果顯示ETag都妥當當的存在,估計目前真的沒有什麼好方法。

只好退而取其次,保證不一樣Server上的ETag一致了。 IIS對Etag的計算算法是ETag = {Filetimestamp:ChangeNumber}, Filetimestamp保持一致沒什麼問題,ChangeNumber是metabase的change number,就有點難保證Cluster中每一個Server都同樣了,因此,乾脆就把它設成固定值好了,這個鏈接告訴咱們該怎麼辦,很惋惜,沒有找到完全刪除ETags的配置。

---------------------------------------------------------------------
相關文章
相關標籤/搜索