2007年8月23日

瀏覽網頁的Cache原理

1.緩衝的基本原理

緩衝服務器是在瀏覽器和網頁服務器之間的一組(台)機器,主要作用有兩個:一是減少網絡流量,二是減少網絡延遲。減少網絡流量主要是減少緩衝服務和原始的網頁服務器之間的流量。減少網絡延遲是減少了應答客戶端瀏覽器的延遲。為了實現這些功能,在HTTP/1.1和HTTP/1.0協議裡面有相關的命令來控制緩衝的行為。

緩衝服務器可以靠近原始服務器端也可以靠近瀏覽器端,靠近服務器端的代理服務器一般叫做反向代理。微睦網絡的代理服務器集群就屬於這種模式。
緩衝服務器利用兩個基本的概念來管理緩存的內容,一是新鮮度,二是有效性檢查。一個被緩存的內容(比如一張圖片)在有效期內,緩衝服務器可以直接把這個內容返回給瀏覽器(客戶端)。如果一個被緩存的內容過期了,那麼緩衝服務器就會認為這個內容是"陳舊"的,就會去原始服務器驗證這個內容是否已經更新。如果已經更新了,那麼就會把更新過的內容下載到緩衝服務器,然後重新開始計算該內容的新鮮時間。

一個內容的過期時間可以由服務器端通過http頭信息來明確指定,比如通過一個名為Expires的http頭來指定,如下面的例子:

http://www.google.com/intl/zh-CN_ALL/images/logo.gif
Expires 1641 weeks 2 days from now (Sun, 17 Jan 2038 19:14:07 GMT)

這是google中國的logo圖片,它的過期時間是2038年1月17日。
那如果這個圖片在中途被修改過了怎麼辦?沒關係,假如一個瀏覽器(比如firefox)對這個圖片進行一下刷新,瀏覽器就會發送一個帶條件的請求,而緩衝就會去真實服務器檢查這個圖片是否已經更新,如果圖片更新了,那麼緩衝服務器就會把新的內容下載過來替代舊的內容。

緩衝服務器驗證內容有效,是通過一些條件來判斷的,比如最後修改時間,或者是一個叫做 ETag 的 http 頭信息。具體的細節就不用去瞭解了。

2. 如何讓你的網頁內容具有更好緩衝友好性

為什麼要對緩衝友好?因為如果有更多的內容被緩衝服務器所緩衝,那麼你的網站本身的負載就降下來了,因為很多請求都由緩衝服務器代你應答了,假如瀏覽器請求下載你的網頁裡的小圖片,如果每個這樣的請求都要你的網頁服務器來處理,必然降低你的網頁服務器的處理能力。

那麼在哪裡設置,如何設置呢?這取決於你使用的網頁服務器,現在流行的就是windows下的IIS和Unix/Linux下的Apache,下面分別講解。

Apache

在Apache裡主要是通過選擇性的模塊來設置頭信息,頭信息是 Expires 和 Cache-Control 模塊是mod_expires 和 mod_headers
利用 httpd -l 命令確認你的apache已經包含了這些模塊;然後就可以在你的配置文件裡使用命令來控制你的內容的新鮮期了。可以對一個目錄設置,也可以對文件類型進行設置。
比如下面的命令將圖片文件的新鮮期設置成1年。更詳細的配置說明請參考apache的文檔。(http://lamp.linux.gov.cn/Apache/ApacheMenu/mod/mod_expires.html)

ExpiresActive on
ExpiresByType image/* "access plus 1 year"

利用這些命令,你可以給你的圖片文件和靜態的文件設置一個合理的新鮮時間。而不用擔心用戶不能看到你最近的更新,正如剛才所說,如果用戶點瀏覽上的刷新按鈕,最新的內容就能被訪問到。

IIS 服務器

在iis管理器中右鍵單擊某一網站或目錄,屬性,http 頭。設置相應的過期策略,對於不經常更新的頁面可設定比較高的值。如2小時,1天等。需要經常更新的數據設定比較小的值,10分鐘,20分鐘。這個時間越長,CDN效果越好,您的真實服務器負載也越小,但有些內容又必須及時刷新,站長可以慢慢調整這個時間,找到一個最佳平衡點.

3. 在CDN後面的真實服務器端如何得到訪問者ip地址

由於真實服務器和瀏覽器之間有CDN的緩衝服務器,真實服務器得到的訪問ip是緩衝服務器的ip地址。但是緩衝服務器通常會在HTTP 頭裡包含真實客戶端的ip地址,在Squid(一種流行的緩衝服務器)裡通常增加一個X-Forwarded-For頭信息來包含原始的客戶端ip.所以要在Apache服務器的日誌裡得到這個ip,可以增加一個%{X-Forwarded-For}i 到相應LogFormat裡面。
如果想在web程序裡得到這個值,可以通過所用語言的相關函數得到這個值,比如說在php裡面,可以利用getenv函數得到。

4.可緩存的動態頁面設計

什麼樣的頁面能夠比較好的被緩衝服務器緩存呢?如果返回內容的HTTP HEADER中有"Last-Modified"和"Expires"相關聲明,比如:

Last-Modified: Wed, 14 May 2003 13:06:17 GMT
Expires: Fri, 16 Jun 2003 13:06:17 GMT

前端緩存服務器在期間會將生成的頁面緩存在本地:硬盤或者內存中,直至上述頁面過期。
因此,一個可緩存的頁面:
頁面必須包含Last-Modified: 標記
一般純靜態頁面本身都會有Last-Modified信息,動態頁面需要通過函數強制加上,比如在PHP中:
// always modified now
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");

必須有Expires或Cache-Control: max-age標記設置頁面的過期時間:
對於靜態頁面,通過apache的mod_expires根據頁面的MIME類型設置緩存週期:比如圖片缺省是1個月,HTML頁面缺省是2天等。

<IfModule mod_expires.c>
ExpiresActive on
ExpiresByType image/gif "access plus 1 month"
ExpiresByType text/css "now plus 2 day"
ExpiresDefault "now plus 1 day"
</IfModule>

對於動態頁面,則可以直接通過寫入HTTP返回的頭信息,比如對於新聞首頁index.php可以是20分鐘,而對於具體的一條新聞頁面可能是1天後過期。比如:在php中加入了1個月後過期:
// Expires one month later
header("Expires: " .gmdate ("D, d M Y H:i:s", time() + 3600 * 24 * 30). " GMT");

如果服務器端有基於HTTP的認證,必須有Cache-Control: public標記,允許前台
ASP應用的緩存改造 首先在公用的包含文件中(比如include.asp)加入以下公用函數:

<%
' Set Expires Header in minutes
Function SetExpiresHeader(ByVal minutes)
' set Page Last-Modified Header:
' Converts date (19991022 11:08:38) to http form (Fri, 22 Oct 1999 12:08:38 GMT)
Response.AddHeader "Last-Modified", DateToHTTPDate(Now())
' The Page Expires in Minutes
Response.Expires = minutes
' Set cache control to externel applications
Response.CacheControl = "public"
End Function
' Converts date (19991022 11:08:38) to http form (Fri, 22 Oct 1999 12:08:38 GMT)
Function DateToHTTPDate(ByVal OleDATE)
Const GMTdiff = #08:00:00#
OleDATE = OleDATE - GMTdiff
DateToHTTPDate = engWeekDayName(OleDATE) & _
", " &amp;amp; Right("0" & Day(OleDATE),2) & " " & engMonthName(OleDATE) & _
" " & Year(OleDATE) & " " & Right("0" & Hour(OleDATE),2) & _
":" & Right("0" & Minute(OleDATE),2) & ":" & Right("0" & Second(OleDATE),2) & " GMT"
End Function
Function engWeekDayName(dt)
Dim Out
Select Case WeekDay(dt,1)
Case 1:Out="Sun"
Case 2:Out="Mon"
Case 3:Out="Tue"
Case 4:Out="Wed"
Case 5:Out="Thu"
Case 6:Out="Fri"
Case 7:Out="Sat"
End Select
engWeekDayName = Out
End Function
Function engMonthName(dt)
Dim Out
Select Case Month(dt)
Case 1:Out="Jan"
Case 2:Out="Feb"
Case 3:Out="Mar"
Case 4:Out="Apr"
Case 5:Out="May"
Case 6:Out="Jun"
Case 7:Out="Jul"
Case 8:Out="Aug"
Case 9:Out="Sep"
Case 10:Out="Oct"
Case 11:Out="Nov"
Case 12:Out="Dec"
End Select
engMonthName = Out
End Function
%>

然後在具體的頁面中,比如index.asp和news.asp的「最上面」加入以下代碼:
HTTP Header
<!--#include file="../include.asp"-->
<%
'頁面將被設置20分鐘後過期
SetExpiresHeader(20)
%>

5. 如何檢驗緩衝服務器如何對待你的網頁內容

打開這個網址:(http://utils.vmmatrix.net/)
然後根據提示,輸入你想檢查的內容的URL(地址),就可以看到這個內容的Http頭信息,和緩衝如何處理這個URL.大多數情況有兩種,一是明確指定了新鮮時間,所以緩衝服務器在新鮮時間內認為這個內容是新鮮的。二是沒有明確指定新鮮時間,緩衝服務器就會根據這個內容的最後修改時間距離現在的時間作為一個時間段,然後把這個時間段的一個百分比來作為新鮮時間,這個百分比是在緩衝服務器哪裡設置的。
如果一個內容既沒有明確指定新鮮時間,也沒有最後修改時間,那麼緩衝服務器就會把這個內容當做是」陳舊「的內容,每次都會去原始服務器驗證。

沒有留言: