1. 程式人生 > >給 Web 開發者與管理員的快取指南

給 Web 開發者與管理員的快取指南

Web 快取是什麼?為什麼要使用快取?

Web 快取處於伺服器(也稱為源伺服器)和客戶端之間,監視請求並儲存響應的副本,比如 HTML 頁面,圖片和檔案等(統稱為表述)。如果之後有對同一個 URL 的新請求,它會使用自己儲存的內容來響應,而不是再次請求源伺服器來獲取內容。

使用 Web 快取主要有下面兩個原因:

  • 減少延遲 —— 因為響應請求的內容來自快取(距客戶端較近)而不是源伺服器,它會花較少的時間來獲得表述並將他們呈現出來。這使得 Web 看起來具有良好的響應速度。

  • 減少網路傳輸 —— 由於複用了表述,它可以減少客戶端使用的頻寬總量。如果客戶需要為流量付費,這就意味著省錢。快取會降低對頻寬的要求,也降低處理難度。

Web 快取的種類

瀏覽器快取

你在檢視現代 Web 瀏覽器(比如 IE、Safari 或 Mazilla)選項的時候,可能會看到“快取”設定。這個選項讓你配置一部分硬碟空間來儲存你看過的表述。瀏覽器快取的規則相當簡單。它通常會在一次會話(即當前瀏覽器中第一次呼叫)中檢查表述是否最新。

這個快取在使用者使用“回退”按鈕或者點選一個瀏覽過的連結時會特別有用。而且,如果你在網站的各個頁面中瀏覽相同的圖片,他們幾乎能馬上從快取中加載出來。

代理快取

Web 代理快取的工作原理相同,但規模更大。代理以同樣的方式為成百上千的使用者服務;大公司和 ISP 常常把程式碼快取建立在防火牆之上,也可能是以獨立裝置的形式存在(也稱為中間裝置

)。

代理快取即不是客戶端的一部分,也不是伺服器的一部分,而是在網路之外,必須以某種方式把請求路由過去。其中一種方式是手工修改瀏覽器代理裝置,指定要使用的程式碼;另一種方式是攔截。攔截式代理會根據其自身的基礎網路重定向 Web 請求,不需要在客戶端配置,客戶端甚至不知道它們的存在。

代理快取是一種共享快取,通常不只是一個使用者,而是大量使用者在使用代理快取。正因為如此,他們特別擅長降低延遲和網路傳輸量。這是因為眾人都需要的表述會被多次重複使用。

閘道器快取

閘道器快取又名“反向代理快取”或“替代快取”。閘道器快取也是一種中介,它他們不是由網路管理員部署以節約頻寬,而是由網站管理員自己部署,使其站點更具伸縮性、可靠性以及擁有更好的效能。

很多方法都可以把請求路由到閘道器快取,但常見的方法是使用負載均衡器讓他們對於客戶來說,看起來就跟源伺服器一樣。

Web快取對我有壞處麼?我為什麼要幫助它們?

Web快取是網際網路中誤解最深的技術之一。因為代理快取可以隱藏使用網站的使用者,所以網站管理員特別害怕失去對他們的站點的控制,這會使得他們很難去知道是誰在使用他們的站點。

然而不幸的是,即使沒有Web快取,網路上也有非常多的因素可以保證管理員精確的知道一個使用者如何使用他們的站點。如果這是你非常關注的問題的話

另一個問題是,快取可以提供已經失去時效性或者無效的資料給請求方。這篇手冊將會演示如何配置你的服務端的服務來控制資料內容的快取方式。

另一方面,如果你把站點規劃的非常好,那麼快取將會使得站點的載入速度更快,同時也會減輕服務端和網路線路的負擔。這兩者之間的區別是非常顯而易見的:一個沒有使用快取的站點可能需要數秒時間來完成頁面的載入和展示,而另一個藉助了快取機制的網站可能在瞬間就完成了頁面載入和展示。而使用者會更喜歡載入速度迅速的站點,同時也會更加頻繁的訪問這些載入迅速的站點。

內容傳遞網路 (CDNs) 是一個非常有意思的發展產物,和通常的代理快取不同的是,CDNs 的閘道器快取和被快取站點的關注點是一致的,所以上述的問題都得到了處理和解決。然而,即便你使用了 CDNs ,你仍然要知道在下游還是會存在代理和瀏覽器快取的。

我們可以這樣想一下:許多大型的網際網路公司為了讓他們的使用者可以在使用其提供的服務時得到最快速的響應,會斥資數百萬美元在世界範圍內建立許多伺服器機群來複制儲存他們的資料內容。其實,快取也能做這些事情,而且,相對來說快取離最終的使用使用者會更近。最好的一點是,你根本不用為此支付任何費用。

而事實是,不管你願意與否,代理和瀏覽器快取都會被使用在某個環節中。如果你沒有正確的配置站點的快取相關配置,站點資料將會按照預設的快取管理員的配置被快取下來。

Web快取是如何工作的?

所有的快取都有一系列用來決定什麼時候從快取中提供內容的規則。如果可能的話,其中的一些規則被放置在了協議中(HTTP 1.0和1.1),而另一些則由快取的管理員(諸如瀏覽器快取的使用者,或者代理管理員)來設定。

通常情況下,下面列出的這些規則是最常用到的規則集(不用擔心你不瞭解規則的詳細嘻嘻,之後會詳細地對這些規則作出解釋):

  1. 如果響應的頭部通知快取不要儲存當前響應內容,那麼快取就不會快取當前響應。

  2. 如果是一個授權的或者加密的請求(例如HTTPS),那麼共享快取將不會儲存相關資料內容。

  3. 在下述場景中,我們認為被快取的內容是最新的(意味著不需要源服務端的檢查就可以被髮送給客戶端),故而資料內容會直接從快取中提供且不需要源服務端的校驗:

    快取內容由過期時間或者其他的生存期控制機制,且快取內容仍在生存有效期內; 如果快取服務近期對外提供了資料內容,且該內容在很久之前就被修改了。
  4. 如果內容已經過時了,源服務端會要求對其進行驗證,或者通知快取服務這份快取的內容是否仍然有效。

  5. 在類似於網路中斷這樣的場景中,快取可以對外提供過時的響應資料而不必和源伺服器進行校驗和確認。

如果在響應中沒有相應的驗證器( ETag 或者 Last-Modified 頭部),且也沒有明確的重新整理資訊,則這種資料通常但不總是的會被視為不可快取的資料。

綜合來看,重新整理和驗證是快取可以正常有效的儲存內容的最重要途徑。新的資料內容可以可靠的快速的從快取中得到,與此同時一個經過驗證的表述則避免了在沒有發生變更的情況下被再次完整的傳送出去。

如何(以及如何不)控制快取

有一些工具可以讓網站設計人員和網站管理員來調整快取對其站點的操作,這可能會使得伺服器的配置發生變更,但是這些變更都是有價值的。對於如何在伺服器上使用這些工具,在實現這一章節會詳細闡述。

HTML Meta 標籤和 HTTP 頭資訊

HTML 作者可以在文件的 <HEAD> 段中放置標籤來描述一些屬性。其中 meta 標籤常用於確保文件不被快取,或者在一定時間後過期。

meta 標籤很容易使用,但效果不怎麼樣。這是因為只有部分瀏覽器快取會遵從約定,代理快取卻不會(代理基本上不會去分析文件中的 HTML)。我們可以在 Web 頁面中放置 Pragma: no-cache 這樣的 meta 標籤,但不要指望他一定會保持重新整理。

另一方面,真正的 HTTP 頭能讓你很好的控制瀏覽器快取和代理快取對錶述內容的處理。HTTP 頭在 HTML 中看不到,它們通常由 Web 服務自動生成。不過你可以在一定程度上控制他們,這取決於你用的是什麼伺服器。你會在下面的部分看到 HTTP 頭是多麼有趣,還會了解到該如何把他們應用到網站上。

如果你的站點託管在 ISP 或者專門的託管服務商那裡,他們不允許你自己設定到頭重要的 HTTP 頭(比如 Expires 和 Cache-Control),那就勇敢地提出抗議,因為你的工作需要這些功能。

HTTP 頭在伺服器傳送 HTML 這前傳送給瀏覽器,只有瀏覽器和中間的快取能夠看到。典型的 HTTP 1.1 響應頭像下面這樣:

HTTP/1.1 200 OK
Date: Fri, 30 Oct 1998 13:19:41 GMT
Server: Apache/1.3.3 (Unix)
Cache-Control: max-age=3600, must-revalidate
Expires: Fri, 30 Oct 1998 14:19:41 GMT
Last-Modified: Mon, 29 Jun 1998 02:28:12 GMT
ETag: "3e86-410-3596fbbc"
Content-Length: 1040
Content-Type: text/html

HTML 會在緊跟在這些頭資訊之後,他們之間用一個空行隔開。在實現以瞭解到設定 HTTP 頭相關的資訊。

Pragma HTTP 頭(以及為什麼它沒用)

很多人認為指定了 Pragma: no-cache HTTP 頭可以避免表述被快取。這並不一定是真的。HTTP 規範中沒有任何關於 Pragma 響應頭的規定,不過 Pragma 請求頭(就是瀏覽器傳送給伺服器的頭資訊)卻正在商討中。雖然有一小部分快取會遵從這個頭資訊,但大多數不會。你應該使用下面這些頭資訊代替它。

使用 Expires HTTP 頭控制新近程度

Expires HTTP 頭是控制快取的基礎方法,它告訴所有快取與之相關的表述存在多久的保鮮期。那保鮮期之後,快取應該檢查源伺服器,看文件是否被改變。幾乎各種快取都支援 Expires 頭。

多數伺服器允許你通過多種方法來設定 Expires 響應頭。一般來說,他們可以設定絕對的過期時間,根據上次客戶端取回表述時(最近訪問時間)計算的時間,或者根據上次伺服器文件修改時間計算的時間(最近修改時間)。

Expires 頭特別適合快取靜態影象(比如導航欄和按鈕),因為他們不會經常變化,你可以為他們設定一個非常長的過期時間,使你的站點具有更優勢的響應效能。對於一些更新比較規律遙頁面來說,他們也很有用。舉例來說,如果你每天早晨 6:00 更新新聞頁面,那就可以把表述內容設定在那個時間過期,然後快取會知道什麼時候該去獲取更新的內容,而不需要使用者去點選“重新整理”。

Expires 頭支援 HTTP 日期值,任何其它值都會被認為“過去時”,結果表述不會被快取。還要注意,HTTP 日期是格林威治(GMT)時間,而不是本地時間。

比如:

Expires: Fri, 30 Oct 1998 14:19:41 GMT

雖然 Expires 頭很有用,但它也有一些侷限。首先日期就是個麻煩事,Web 伺服器和快取上的時鐘就必須同步。如果他們對時間的看法不一致就達不到預期的效果,因為快取有可能認為已經過期的內容還在有效期內。

如果使用Expires 頭就必須保證伺服器時鐘的準確性,這非常重要。要達到這個條件,有一個辦法是使用網路時間協議(NTP),請向你身邊的系統管理員瞭解關於 NTP 的知識。

使用 Expires 的另一個問題是容易忘記為某些內容設定了特定的過期時間。如果你沒有在那之前更新 Expires,那麼每個請求最終都會到伺服器上去獲取內容,既增加延遲,也會增加負載。

Cache-Control HTTP 頭

HTTP 1.1 引入了一類新的頭信, Cache-Control 響應頭,讓 Web 可以更方便地控制內容,避免 Expires 所具有的限制。

Cache-Control 響應頭有如下一些:

  • max-age=[秒] — 指定表述內容的最大有效期。跟 Expires 類似,這個指令的時間是相對於請求時間,而不是絕對時間。[秒] 是從請求開始你期望表述過期前保持有效的總秒數。

  • s-maxage=[秒] — 和 max-age 相似,但它只對共享(例如代理)快取有效。

  • public — 把通過認證的響應標記為可快取。一般情況下,如果需要 HTTP 認證,響應會自動標記為私有的。

  • private — 允許使用者(比如一個瀏覽器)快取響應,不允許共享快取(比如代理)進行快取。

  • no-cache — 強制快取將請求提交到原伺服器進行驗證後釋放快取副本,一次不落。這可以確保謹慎地對待認證(結合 public 標記),嚴謹地更新,同時又不犧牲快取所帶來的各種好處。

  • no-store — 指示快取在任何情況下都不保留表述的副本。

  • must-revalidate — 告訴快取,他們必須遵守你給他們關於內容更新的每一項資訊。HTTP 允許快取服務在一些特殊情況下認為表述過期,你可以通過指定這個頭引數告訴快取你希望它嚴格遵守你的規則。

  • proxy-revalidate — 與 must-revalidate 相似,但它只對代理快取有效。 

舉例說明:

Cache-Control: max-age=3600, must-revalidate

校驗器和校驗

在Web 快取的工作原理一文中,我們說過在表示層發生變化時伺服器和快取使用校驗進行通訊。通過使用它,快取可以避免在本地已有副本時下載整個表示層,但他們不確定它是否仍然是最新的。

校驗器是非常重要的; 如果它不存在,並且沒有任何新的資訊( Expires 或 Cache-Control )可用,則快取將根本不儲存表示層。

最通用的校驗器是頭部的 Last-Modified,用來標識文件最近一次修改的時間。如果快取儲存了一個帶有Last-Modified 頭部的表示層,快取可以藉助一個 If-Modified-Since 請求向服務端確認當前快取的表示層在最近一次修改後是否發生了變更。

HTTP1.1引入了一個新的叫做 ETag 的校驗器。ETags是一個由服務端生成的唯一識別符號,並且每當表示層發生變更時ETags的值都會發生變化。由於ETag是由服務端生成的,所以當快取通過 If-None-Match 請求得知ETag在服務端匹配成功時,便可以確認快取儲存的表示層和服務端的內容是一致的,沒有發生任何變化。

幾乎所有的快取都使用了最近一次修改時間來作為校驗器,同時ETag校驗器的使用也在逐步增長。

大多數的現代網站伺服器會自動地為靜態內容(例如檔案)同時生成 ETag 和 Last-Modified 這兩個校驗器,這個過程不需要任何人為參與。然而,伺服器在為諸如CGI、ASP或者資料庫站點這樣的動態內容生成ETag 和 Last-Modified 校驗器時就顯得力不從心了,具體可瀏覽編寫快取可感知的指令碼。

關於構建一個快取感知的站點的忠告

除了使用新鮮度資訊和校驗,還有一些其他的處理可以使得你的站點更利於快取。

  • 始終使用URL - 這一條是快取的黃金原則。如果向不同的頁面、不同的使用者提供同樣的資料內容,或者同樣的內容來自於不同的站點,這時應該使用一致的URL。這是最簡單、最有效的讓站點更利於快取的方法。例如,如果一旦在HTML程式碼段中使用"/index.html"作為一個資源引用,那麼就一直按照這種方式堅持下去。

  • 使用一個包含圖片和其他元素的公共庫,並在不同的地方引用他們。

  • 使用快取來儲存圖片和很少變更的頁面,這個的實現可以藉助一個設定了很大的值的 Cache-Control: max-age 頭部資訊。

  • 通過一個精確的最大存活時間或者過期時間讓快取識別出更新頻繁的頁面。

  • 如果資源(特別是可下載的檔案)發生了變更,改變其名字。通過這種方式,可以讓資源在未來的某個時間過期,同時也能保證當前版本仍然是有效的。唯一需要設定一個短的過期時間的部分就是連結到這些資源的頁面。

  • 在必要的情況下再修改檔案。如果你這麼做了,那麼每個檔案都會有一個不真實的距離當前時間更近的 Last-Modified 值。舉個例子,當準備更新站點時,不要複製整個站點檔案進行更新,僅選擇那些確實修改了的檔案去執行更新操作。

  • 只在有需要的情況下使用cookie。cookies很難被快取儲存起來,並且在大多數場景都是沒有必要的。如果必須用到cookie的話,那麼也只在動態頁面中使用cookie。

  • 用REDbot檢查頁面檔案。這個工具可以協助站點開發管理人員應用上文中討論過的諸多原則。

編寫快取可感知的指令碼

預設情況下,大多數指令碼不會返回校驗器(一個 Last-Modified 或 ETag 響應頭)或新鮮度資訊( Expires 或 Cache-Control )。雖然一些指令碼確實是動態的(意味著它們為每個請求返回不同的響應),但許多(如搜尋引擎和資料庫驅動的網站)可以從此類快取友好中受益。

一般來說,如果指令碼生成的輸出在以後的某個時間(無論是幾分鐘還是幾天後)都可以使用相同的請求重現,那麼它應該是可快取的。如果指令碼的內容僅根據 URL 中的內容而變動,則它是可快取的; 如果其輸出取決於cookie、身份認證資訊或其他外部標準,則它可能不是可快取的。

  • 讓指令碼對快取友好(同時有更好的表現)的最佳方式是隻要指令碼發生變化,就將其內容轉儲到一個普通檔案中。Web 伺服器會把這個檔案跟其它 Web 頁面同等對待,為其生成驗證器,讓一切變得簡單。記住,只寫內容變動過的檔案,避免重新整理新沒有內容變動檔案的 Last-Modified 時間。

  • 還有一種方法可以讓指令碼在一定的限制條件下被快取,即設定一個跟壽命相關的頭。雖然用 Expires 可以做到,但用 Cache-Control: max-age 可能更簡單,它會按一定時間間隔重新整理請求。

  • 如果這些辦法都不適合你,那你需要用指令碼生成一個驗證器,然後響應 If-Modified-Since 或 If-None-Match 請求。這個操作可以通過解析 HTTP 頭之後,適當的響應 304 Not Modified 來實現。不過操作起來似乎不簡單。

其它技巧:

  • 不使用 POST,除非確有必要。多數快取不會儲存 POST 響應。如果你通過路徑或查詢(通過 GET)傳送資訊,快取會儲存這些資訊以備將來使用。

  • 不要在 URL 中嵌入使用者特定的資訊,除非生成的內容對每個使用者都不同。

  • 不要以為所有使用者請求都來自同一臺主機,因為也有可能來自快取。

  • 生成 Content-Length 響應頭。這很容易做到,而且它會允許通過長連線來響應指令碼。這樣一來,客戶端可以在一個 TCP/IP 連線上請求多個表述,而不是為每個請求建立連線。這樣你的網站看起來會更快。

FAQs (常見問題)

實現可快取最重要的事情是什麼?

一個好的策略是識別最流行、最大的表示層(尤其是影象)並首先在它們上使用。

我如何使用快取儘可能快地載入頁面?

最可快取的表示層是具有較長新鮮時間集的那一部分。校驗確實有助於減少查看錶示層所花費的時間,但快取仍然必須聯絡原伺服器以檢視它是否是最新的。 如果快取已經知道它是最新的,它將被直接提供。

我知道快取很棒,但我需要統計有多少人訪問了我的頁面!

如果在每次訪問頁面時你都必須知悉,在頁面(或頁面本身)上選擇 ONE 小項,並通過為其提供適當的頭資訊使其不可快取。例如,你參考每個頁面上的 1x1 透明的不可快取影象的邏輯。Referer 頭將包含有關哪個頁面呼叫它的資訊。

請注意,即使這樣也無法提供有關你使用者的真實準確的統計資訊,並且對網際網路和你的使用者是不友好的; 它會產生不必要的流量,並強迫人們等待下載完成未快取項。

如何獲取一個表示層的HTTP頭部資訊?

許多瀏覽器會通過一個“page info”或者一個小型的介面等方式向使用者提供  Expires 和 Last-Modified 的頭部資訊。如果可以的話,你會得到一個頁面的選單和關聯在這個頁面上的任何表示層(比如影象),以及這些表示層的詳細資訊。

如果想要看到表示層的所有HTTP頭部資訊,可能需要使用Telnet客戶端手動連線到Web伺服器上。

要想通過Telnet連線到伺服器上,需要把埠號(預設80)作為一個獨立的欄位輸入到連線到請求中,需要以如下的形式連線到伺服器上: www.example.com:80 或者 www.example.com 80(以空格分隔) 。具體格式可以參考你使用的客戶端文件。

一旦連線成功建立,就可以對任意表示層發起請求。例如,如果你想要獲得 http://www.example.com/foo.html 的所有頭部資訊,連線到 www.example.com,埠號是 80,並且輸入:

GET /foo.html HTTP/1.1 [return]
Host: www.example.com [return][return]

每次當你看到 [return] 提示時,就按下回車鍵,確保在結束之前要按夠兩次回車。這個操作就會打印出對應的頭部資訊,緊隨其後的是整個完成的表示層資訊。如果只是想頭部資訊的話,用 HEAD 代替 GET 即可。

我的頁面是受密碼保護的,代理快取怎麼處理這種情況?

預設情況下,受HTTP身份認證保護的頁面被視為是私有的,這些頁面不會被共享快取儲存下來。然而,可以通過快取控制(Cache-Control): public 頭部使受身份認證保護的頁面變成共有資源,適用於HTTP1.1的快取就會將這些頁面快取下來。

如果你想讓這些頁面既能被快取儲存的同時又能繼續保持其對每個使用者的身份認證特性,就需要將 Cache-Control: public 和 no-cache 結合起來使用。這兩個頭部會要求快取取出表示層資料返回給請求之前首先將使用者的身份資訊提交給伺服器進行認證。命令格式如下:

Cache-Control: public, no-cache

不管上面的處理執行與否,最好的方式是最小化認證保護的使用範圍。例如,如果圖片資料是非敏感資料,那麼將這些圖片放在一個獨立的資料夾目錄下,然後在服務端配置不對這個資料夾目錄做身份認證保護。這樣,這些圖片就可以被快取儲存起來了。

如果人們通過快取訪問我的站點,我需要擔心安全性嗎?

https:// 頁面是不會被代理快取快取(或解密)的,因此你不必擔心這一點。然而,因為快取儲存了從獲取的 http:// 響應和 URL ,所以你應該對不安全的站點小心一些; 一個不道德的管理員可以隨意地收集有關其使用者的資訊,尤其是在 URL 中。

實際上,在伺服器和客戶端之間的網路上的任何管理員都可以收集此類資訊。一個特別的問題是 CGI 指令碼將使用者名稱和密碼放在 URL 本身中; 這使得其他人找到並使用這些登入資訊變得很簡單。

如果你知道常見的 Web 安全性所存在的問題,那麼代理快取不應該有任何例外。

我正在尋找一個整合 Web 釋出解決方案。哪一個是快取可感知的?

這要看具體情況。一般來說,解決方案越複雜,快取起來就越困難。最糟糕的是動態生成所有內容並不提供校驗器的解決方案; 它們可能根本是不可快取的。請與供應商的技術人員聯絡以獲取更多資訊,並參閱下面的實現說明。

我的圖片在一個月以後才失效,但是我需要現在就在快取中更新它們!

過期(Expires)頭部是沒有辦法繞過去的,快取內容會一直被使用直到快取(不管是瀏覽器快取還是代理快取)耗盡了儲存空間並且必須刪除掉所有的表示層。

最有效的解決方法是改變任何指向它們的連結,這樣,全新的表示層會從源服務端載入到客戶端。記住,任何引用了這些表示層的頁面也會被快取儲存下來。鑑於此,最好將靜態圖片和相似的表示層全都快取下來,同時嚴格把控引用這些資源的HTML頁面。

如果想要從某個指定的快取中重新載入一個表示層,你既可以在使用快取的時候強制載入(在Firefox中,按下shift的同時按下‘reload’將發出一個 Pragma: no-cache請求頭部來完成這個操作),也可以讓快取管理員通過他們的介面刪除掉這個表示層。

如何讓使用者在我負責維護的網站託管服務上釋出快取友好的頁面?

如果你使用的的Apache,考慮下容許他們使用 .htaccess檔案並且提供對應的文件。

否則,你可以建立一個事先決定好的區域,這個區域用來對應每個虛擬服務上的各種快取屬性。例如,可以指定一個 /cache-1m 目錄來維護需要在訪問後快取一個月的快取內容的相關資訊,一個 /no-cache 目錄通過使用頭部資訊標識那些不需要快取儲存來自其自身的表示層。

不管你能做什麼,最好首先在快取方面和你的最大的客戶一起合作。大部分的節省(頻寬和伺服器負載方面)會從高流量站點中產生。

頁面是可快取的,但是瀏覽器在每次請求時都會重新請求這些頁面。怎麼樣可以強制快取儲存這些表示層?

快取不需要保留或者重用一個表示層,它只需要在某些情況下不保留或者使用它們。基於表示層的檔案大小、型別(圖片或者HTML檔案)、以及它們需要佔用的儲存空間大小,快取會決定哪些表示層會被儲存下來。相對於更受歡迎或者更大的表示層,快取認為你的內容可能不值得被快取儲存起來。

一些快取機制允許管理員決定哪些表示層可以優先被快取,而另外一些快取機制則允許表示層可以被固定在快取中,這樣它們就總是有效的表示層。

實施說明 — Web 伺服器

一般來說,不管你想部署到哪個 Web 伺服器,最好都選擇它最新的版本。新版本可能會包含更易於處理快取的特性,而且通常還會在非常重要的安全和效能方面所有改進。

模組需要設定到 Apache 中。雖然模組被包含在發行包中,但預設情況下並未設定可用。想知道某個模組是否在伺服器中可用,找到 https 二進位制程式然後執行httpd -l。這個命令會打印出已經生效的模組列表(注意這隻包含了隨 Apache 編譯的模組。在以後的 Apache 版本中,可以使用 httpd -M 把動態載入的模組也打印出來)。我們要找 expires_module 和 headers_module 這兩個模組。

  • 如果他們還未生效,你在有管理員許可權的情況下可以重新編譯 Apache 以包含他們。只需要在配置檔案中找到恰當的行,取消掉他們的註釋就行,也可以使用 -enable-module=expires 和 -enable-module=headers 這兩個引數來配置(1.3 或更高的版本)。欲知詳情,請查閱 Apache 發行的 INSTALL 檔案。

一旦你的 Apache 包含了正確的模組,就可以使用 mod_expires 來指定表述到期的時間,這個配置寫在 .htaccess 檔案或者伺服器的 asccess.conf 檔案中都行。你可以按訪問時間或修改時間來指定過期時間,可以將其應用於某個檔案型別,也可以用作預設配置。

要應用Cache-Control頭,你需要使用mod_headers模組,該模組允許你為某資源指定任意HTTP頭。 請參閱mod_headers文件。

這是一個示例.htaccess檔案,展示了一些頭的使用。

  • .htaccess檔案允許Web釋出者使用通常僅在配置檔案中可找到的命令。它們會影響它們所在目錄及其子目錄的內容。與伺服器管理員溝通下,瞭解它們是否已被啟用。

### activate mod_expires
ExpiresActive On
### Expire .gif's 1 month from when they're accessed
ExpiresByType image/gif A2592000
### Expire everything else 1 day from when it's last modified
### (this uses the Alternative syntax)
ExpiresDefault "modification plus 1 day"
### Apply a Cache-Control header to index.html
<Files index.html>
Header append Cache-Control "public, must-revalidate"
</Files>
  • 注意mod_expires會在合適時機自動計算並插入一個Cache-Control:max-age頭。

Apache 2的配置和1.3版本的非常類似;更多資訊請參考2.2mod_expires和mod_headers文件。

微軟的IIS

Microsoft的Internet Information Server以一種靈活的方式使得設定頭資訊變得非常容易。請注意,這僅適用於伺服器的第4版,該版本僅在NT Server上執行。

要指定站點區域的頭資訊,請在“Administration Tools”介面中選擇它,然後調出其屬性。在選擇HTTP Headers選項卡之後,你應該看到兩個有趣的區域; Enable Content ExpirationCustom HTTP headers。第一個區域應該是不言自明的,第二個可以用於適用於Cache-Control頭。

有關在Active Server Pages中設定頭的資料,請參閱下面的ASP部分。也可以從ISAPI模組設定頭; 有關詳細資訊,請參考MSDN。

Netscape/iPlanet企業伺服器

從版本3.6開始,企業伺服器不再提供任何顯式的方法來設定Expires頭。但是,它從3.0開始就支援HTTP 1.1功能。這意味著HTTP 1.1快取(代理和瀏覽器)將能夠利用你所做的快取控制配置。

要使用Cache-Control頭,請選擇管理伺服器中的Content Management | Cache Control Directives。 然後,使用資源選擇器,選擇要設定頭的目錄。

實現附註— 伺服器端指令碼

由於伺服器端指令碼的重點在於動態內容,因此即使是對可快取的內容,也不會生成可快取的頁面。如果你的內容經常變動,但不是每次點選都會變動,請考慮設定Cache-Control:max-age頭; 大多數使用者在相對較短的時間內再次訪問該頁面。例如,當用戶點選“後退”按鈕時,如果沒有任何校驗器或新鮮度資訊可用,則他們必須等到從伺服器重新下載頁面之後才能看到它。

要記住的一件事是,使用Web伺服器時設定HTTP比在指令碼語言中設定HTTP標頭更容易。都嘗試下。

CGI

CGI指令碼是最常用的生成內容的方式之一。你可以通過在傳送正文之前新增HTTP響應頭輕鬆得附加到HTTP響應頭上;大多數CGI實現已經要求你為Content-Type頭執行此操作。例如,在Perl中;

#!/usr/bin/perl
print "Content-type: text/html\n";
print "Expires: Thu, 29 Oct 1998 17:04:19 GMT\n";
print "\n";
### the content body follows...

既然它全是文字,你可以簡單地使用內建函式生成Expires以及其他日期相關的頭資訊。如果你使用Cache-Control: max-age將會更簡單;

print "Cache-Control: max-age=600\n";

這將使此指令碼在請求後可快取10分鐘,因此如果使用者點選“後退”按鈕,他們將不會重新提交請求。

CGI規範還使得在指令碼環境中客戶端所傳送的請求頭可用; 每個標頭的名稱前面都有“HTTP_”。因此,如果客戶端發出If-Modified-Since請求,它將顯示為HTTP_IF_MODIFIED_SINCE

Server Side Includes

SSI(通常與副檔名為.shtml的一起使用)是Web釋出者能夠將動態內容新增到頁面中的首選方式之一。通過在頁面中使用特殊標記,可以使用有限形式的HTML內指令碼。

大多數SSI實現都沒有設定校驗器,因此SSI是不能快取。 但Apache的實現允許使用者通過在適當的檔案上設定組執行許可權並結合XbitHack full指令來指定可以快取哪些SSI檔案。