http://www.ibm.com/developerworks/cn/web/wa-aj-cache/
簡介
随着 Web 2.0 應用程式的出現和流行,Internet 的使用方式已經發生改變,出現了一種新趨勢:針對内容管理、資訊共享、通信、團隊合作等建立一種更加以使用者為中心的方法。從技術角度看,Web 2.0 應用程式并沒有帶來很多新的技術突破。但是,這些應用程式的确帶來了一種新的 Internet 使用模式。現在,Web 2.0 應用程式擁有許多典型特征,包括擁有富用戶端、大頁面、包含許多小項目的頁面、大量的 JavaScript 編碼等等。這些特征會導緻浏覽器端性能問題,特别是在長距離網絡中。這些性能問題會對使用者體驗造成不利影響,但您甚至不會意識到這些問題的存在。由于開發人員擁有很好的網絡條件,是以這些性能問題很難完全暴露出來。
本文将首先分析典型的 Web 2.0 應用程式的關鍵方面,解釋它們如何影響浏覽器端性能。然後,本文介紹浏覽器端性能的一個非常重要的部分 —— 浏覽器緩存。通過使用适當的緩存設定,您可以向使用者提供較好的應用程式體驗。如果您沒有一個整體緩存政策設計,那麼您的緩存政策不僅會導緻低劣的性能,還會引發一些功能缺陷。
有許多影響浏覽器緩存的規則,其中的部分規則包括 Cache-Control、Etag、Expires、Last-Modified 和 Vary。所有這些設定擁有不同的含義和最适用的情形。困難之處在于對于相同的設定,并不是所有流行浏覽器都擁有相同的行為。是以,在您決定使用這些設定之前,您應該準确了解這些浏覽器是如何工作的。本文将檢查目前市面上最流行的浏覽器的行為:Internet Explorer、Firefox、Chrome 和 Safari。
在本文中,我們還使用 IBM® Mashups 和開源 “Roller Weblogger” 來提供一些示例,展示如何應用不同的指令以最好地使用浏覽器緩存。
背景
在當今的 Internet 環境中,Web 2.0 應用程式正在變得越來越流行。許多 Web 站點都使用 Web 2.0 建構,比如 Facebook、Youtube 等。IBM 也有 Web 2.0 應用程式,比如 Lotus Connections 和 Lotus Mashups。
以下是一種用于計算浏覽器響應時間的基本方法:
- 浏覽器響應時間 = 伺服器端時間 + 頁面加載時間 + 浏覽器呈現時間
- 頁面加載時間 = (請求數 / 并發數)* 延遲時間 + 頁面總大小 / 帶寬
在上述等式中:
- “伺服器端時間” 是指伺服器端處理所花費的時間,比如通過 LDAP 驗證和從資料庫檢索資訊。
- “浏覽器呈現時間” 是指浏覽器呈現頁面所花費的時間,包括執行 JavaScript 和解析 DOM 樹的時間。
- “請求數” 是指 HTTP 請求的數量。
- “并發數” 是指浏覽器與伺服器之間的并行連接配接的數量。
- “頁面總大小” 是指一個頁面的完整大小。
- “延遲時間” 和 “帶寬” 是網絡狀态名額。在常見的長距離網絡環境中,帶寬大約為 1M,延遲時間大約為 100 毫秒。是以,減少到 100KB 或減少為一個請求能夠節約 0.1 秒響應時間。
請注意一點,鑒于真實環境的複雜性,這個等式可能不能涵蓋所有情形。
在一個典型的 Web 2.0 富 Internet 應用程式(例如 Lotus Mashup Maker)中,浏覽器首先發送格式定義請求到伺服器。接收到定義響應資料後,浏覽器向伺服器發送資料請求。然後,浏覽器對使用者呈現頁面。在這種模式中,有大量的小項目請求,比如 JavaScript 檔案、CSS 檔案等。在長距離網絡環境中,這會導緻嚴重影響使用者體驗的用戶端性能問題。大多數檔案是可以被緩存的靜态檔案,是以,如果您添加适當的緩存控件、expiry 頭部以及其他影響浏覽器緩存的頭部中繼資料,就可以明顯改善使用者體驗。
浏覽器緩存機制
有幾個影響浏覽器緩存的規則,這個小節将分别讨論它們。
Cache-Control
Cache-Control 是最重要的規則。這個字段用于指定所有緩存機制在整個請求/響應鍊中必須服從的指令。這些指令指定用于阻止緩存對請求或響應造成不利幹擾的行為。這些指令通常覆寫預設緩存算法。緩存指令是單向的,即請求中存在一個指令并不意味着響應中将存在同一個指令。
cache-control 定義是:Cache-Control = "Cache-Control" ":" cache-directive。表 1 展示了适用的值。
表 1. 常用 cache-directive 值
Cache-directive | 說明 |
---|---|
public | 所有内容都将被緩存 |
private | 内容隻緩存到私有緩存中 |
no-cache | 所有内容都不會被緩存 |
no-store | 所有内容都不會被緩存到緩存或 Internet 臨時檔案中 |
must-revalidation/proxy-revalidation | 如果緩存的内容失效,請求必須發送到伺服器/代理以進行重新驗證 |
max-age=xxx (xxx is numeric) | 緩存的内容将在 xxx 秒後失效 |
表 2 表明在不同的情形下,浏覽器是将請求重新發送到伺服器還是使用緩存的内容。
表 2. 對 cache-directive 值的浏覽器響應
Cache-directive | 打開一個新的浏覽器視窗 | 在原視窗中單擊 Enter 按鈕 | 重新整理 | 單擊 Back 按鈕 |
---|---|---|---|---|
public | 浏覽器呈現來自緩存的頁面 | 浏覽器呈現來自緩存的頁面 | 浏覽器重新發送請求到伺服器 | 浏覽器呈現來自緩存的頁面 |
private | 浏覽器重新發送請求到伺服器 | 第一次,浏覽器重新發送請求到伺服器;此後,浏覽器呈現來自緩存的頁面 | 浏覽器重新發送請求到伺服器 | 浏覽器呈現來自緩存的頁面 |
no-cache/no-store | 浏覽器重新發送請求到伺服器 | 浏覽器重新發送請求到伺服器 | 浏覽器重新發送請求到伺服器 | 浏覽器重新發送請求到伺服器 |
must-revalidation/proxy-revalidation | 浏覽器重新發送請求到伺服器 | 第一次,浏覽器重新發送請求到伺服器;此後,浏覽器呈現來自緩存的頁面 | 浏覽器重新發送請求到伺服器 | 浏覽器呈現來自緩存的頁面 |
max-age=xxx (xxx is numeric) | 在 xxx 秒後,浏覽器重新發送請求到伺服器 | 在 xxx 秒後,浏覽器重新發送請求到伺服器 | 浏覽器重新發送請求到伺服器 | 在 xxx 秒後,浏覽器重新發送請求到伺服器 |
Cache-Control 是關于浏覽器緩存的最重要的設定,因為它覆寫其他設定,比如 Expires 和 Last-Modified。另外,由于浏覽器的行為基本相同,這個屬性是處理跨浏覽器緩存問題的最有效的方法。
失效
Expires 頭部字段提供一個日期和時間,響應在該日期和時間後被認為失效。失效的緩存條目通常不會被緩存(無論是代理緩存還是使用者代理緩存)傳回,除非首先通過原始伺服器(或者擁有該實體的最新副本的中介緩存)驗證。(注意:cache-control max-age 和 s-maxage 将覆寫 Expires 頭部。)
Expires 字段接收以下格式的值:“Expires: Sun, 08 Nov 2009 03:37:26 GMT”。如果檢視内容時的日期在給定的日期之前,則認為該内容沒有失效并從緩存中提取出來。反之,則認為該内容失效,緩存将采取一些措施。表 3-6 表明針對不同使用者操作的不同浏覽器的行為。
表 3. 當使用者打開一個新的浏覽器視窗時的失效操作
Firefox 3.5 | IE 8 | Chrome 3 | Safari 4 | |
---|---|---|---|---|
内容沒有失效 | 浏覽器呈現來自緩存的頁面 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器呈現來自緩存的頁面 | 浏覽器呈現來自緩存的頁面 |
内容失效 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 |
表 4. 當使用者在原始浏覽器視窗中單擊 Enter 按鈕時的失效操作
Firefox 3.5 | IE 8 | Chrome 3 | Safari 4 | |
---|---|---|---|---|
内容沒有失效 | 浏覽器呈現來自緩存的頁面 | 浏覽器呈現來自緩存的頁面 | 浏覽器重新發送請求到伺服器。傳回代碼是 304 | 浏覽器重新發送請求到伺服器。傳回代碼是 304 |
内容失效 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器呈現來自緩存的頁面 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 |
表 5. 當使用者按 F5 鍵重新整理頁面時的失效操作
Firefox 3.5 | IE 8 | Chrome 3 | Safari 4 | |
---|---|---|---|---|
内容沒有失效 | 浏覽器重新發送請求到伺服器。傳回代碼是 304 | 浏覽器重新發送請求到伺服器。傳回代碼是 304 | 浏覽器重新發送請求到伺服器。傳回代碼是 304 | 浏覽器重新發送請求到伺服器。傳回代碼是 304 |
内容失效 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 |
表 6. 當使用者單擊 Back 或 Forward 按鈕時的失效操作
Firefox 3.5 | IE 8 | Chrome 3 | Safari 4 | |
---|---|---|---|---|
内容沒有失效 | 浏覽器呈現來自緩存的頁面 | 浏覽器呈現來自緩存的頁面 | 浏覽器呈現來自緩存的頁面 | 浏覽器呈現來自緩存的頁面 |
内容失效 | 浏覽器呈現來自緩存的頁面 | 浏覽器呈現來自緩存的頁面 | 浏覽器呈現來自緩存的頁面 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 |
注意:所有浏覽器都假定為使用預設設定運作。
Last-Modified/E-Tag
Last-Modified 實體頭部字段值通常用作一個緩存驗證器。簡單來說,如果實體值在 Last-Modified 值之後沒有被更改,則認為該緩存條目有效。ETag 響應頭部字段值是一個實體标記,它提供一個 “不透明” 的緩存驗證器。這可能在以下幾種情況下提供更可靠的驗證:不友善存儲修改日期;HTTP 日期值的 one-second 解決方案不夠用;或者原始伺服器希望避免由于使用修改日期而導緻的某些沖突。
不同的浏覽器有不同的配置行為。表 7-10 表明針對不同使用者操作的不同浏覽器的行為。
表 7. 當使用者打開一個新的浏覽器視窗時的 Last-Modified E-Tag 操作
Firefox 3.5 | IE 8 | Chrome 3 | Safari 4 | |
---|---|---|---|---|
内容自上次通路以來沒有被修改 | 浏覽器重新發送請求到伺服器。傳回代碼是 304 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 304 | 浏覽器重新發送請求到伺服器。傳回代碼是 304 |
内容自上次通路以來已經被修改 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 |
表 8. 當使用者在原始浏覽器視窗中單擊 Enter 按鈕時的 Last-Modified E-Tag 操作
Firefox 3.5 | IE 8 | Chrome 3 | Safari 4 | |
---|---|---|---|---|
内容自上次通路以來沒有被修改 | 浏覽器呈現來自緩存的頁面 | 浏覽器呈現來自緩存的頁面 | 浏覽器重新發送請求到伺服器。傳回代碼是 304 | 浏覽器重新發送請求到伺服器。傳回代碼是 304 |
内容自上次通路以來已經被修改 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器呈現來自緩存的頁面 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 |
表 9. 當使用者按 F5 鍵重新整理頁面時的 Last-Modified E-Tag 操作
Firefox 3.5 | IE 8 | Chrome 3 | Safari 4 | |
---|---|---|---|---|
内容自上次通路以來沒有被修改 | 浏覽器重新發送請求到伺服器。傳回代碼是 304 | 浏覽器重新發送請求到伺服器。傳回代碼是 304 | 浏覽器重新發送請求到伺服器。傳回代碼是 304 | 浏覽器重新發送請求到伺服器。傳回代碼是 304 |
内容自上次通路以來已經被修改 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 |
表 10. 沒有緩存設定且使用者單擊 Back 或 Forward 按鈕
Firefox 3.5 | IE 8 | Chrome 3 | Safari 4 | |
---|---|---|---|---|
内容自上次通路以來沒有被修改 | 浏覽器呈現來自緩存的頁面 | 浏覽器呈現來自緩存的頁面 | 浏覽器呈現來自緩存的頁面 | 浏覽器呈現來自緩存的頁面 |
内容自上次通路以來已經被修改 | 浏覽器呈現來自緩存的頁面 | 浏覽器呈現來自緩存的頁面 | 浏覽器呈現來自緩存的頁面 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 |
注意:所有浏覽器都假定使用預設設定運作。
不進行任何緩存相關設定
如果您不定義任何緩存相關設定,則不同的浏覽器有不同的行為。有時,同一個浏覽器在相同的情形下每次運作時的行為都是不同的。情況可能很複雜。另外,有些不該緩存的内容如果被緩存,将會導緻安全問題。
不同的浏覽器有不同的行為。表 11 展示了不同的浏覽器行為。
表 11. 沒有緩存設定且使用者打開一個新的浏覽器視窗
Firefox 3.5 | IE 8 | Chrome 3 | Safari 4 | |
---|---|---|---|---|
打開一個新頁面 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 |
在原始視窗中單擊 Enter 按鈕 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器呈現來自緩存的頁面。 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 |
按 F5 鍵重新整理 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 |
單擊 Back 或 Forward 按鈕 | 浏覽器呈現來自緩存的頁面。 | 浏覽器呈現來自緩存的頁面。 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 | 浏覽器重新發送請求到伺服器。傳回代碼是 200 |
注意:所有浏覽器都假定使用預設設定運作。
應用示例
本小節提供幾個 Web 站點分析示例,展示如何使用 IBM 商業和開源工具确定正确的緩存行為。
Apache Roller Weblogger
Apache Roller Weblogger 是一個開源 Web 2.0 Web 應用程式,它是驅動 blogs.sun.com、blog.usa.gov、IBM Lotus Connections、IBM Developer Works 部落格等大量部落格的開源 Java™ 部落格伺服器,
在本文中,我們選擇 IBM My developerWorks 部落格作為一個示例,詳細解釋緩存設定。圖 1 展示了 My developerWorks 部落格頁面的一個螢幕截圖。
圖 1. My developerWorks 部落格頁面
這個頁面有 62 個請求,多數是 png、gif、js 或其他靜态檔案類型。當使用者首次通路這個頁面時,将花費約 16 秒時間來在浏覽器中顯示整個頁面。如果您定義正确的緩存設定,多數資源将被緩存到浏覽器端。是以,當使用者再次通路這個頁面時,這個頁面的請求數量将減少到 22,隻需約 6 秒鐘就可以加載。使用者體驗得到極大地改善。
現在,我們将分析一些重要的請求緩存設定。相關的 Weblogger 輸出如圖 2 所示。
圖 2. My developerWorks 部落格首頁 Response Header 1
首先,Cache-Control 覆寫 Last-Modified 設定,是以頁面可以在本地緩存 5 秒鐘,但如果内容失效将重新驗證。當使用者通路這個頁面時,浏覽器首先檢查本地緩存,以确定本地檔案是否已經失效。如果内容失效,浏覽器将發送一個請求到伺服器以比較 Last-Modified 時間戳。如果響應檔案擁有相同的 Last-Modified 時間戳,則伺服器将傳回代碼 304 到浏覽器,告知浏覽器響應檔案相同。
圖 3. My developerWorks 部落格首頁 Response Header 2
這個 Cache-Control 設定表明:這個響應不能被緩存。從業務角度看,這個請求用于檢查使用者驗證和授權,不應該被緩存。
圖 4. My developerWorks 部落格首頁 Response Header 3
這個響應檔案是一個很少修改的 JavaScript 庫,是以它的 max-age 等于 1 天。
Mashup Center
Mashup Center 設計用于提供一個易于使用的 mashup 解決方案,支援将多個動态情景應用程式集合到一個業務範圍中,并提供 IT 所需的安全和治理功能。Mashup Center 包含 Lotus Mashups 和 InfoSphere MashupHub。圖 5 展示了正在運作的 Lotus Mashups 的快照。
圖 5. Mashup 首頁
圖 6 和圖 7 展示了選中的 HTTP 頭部。
圖 6. Mashup 首頁 Response Header 1
這個請求檢索可以從伺服器緩存的主題資訊。
圖 7. Mashup 首頁 Response Header 2
這是一個個人首頁,不應該被緩存。注意,Expires 日期值設定為一個很久以前的日期,以便這個頁面總是能夠重新整理。
結束語
由于不同浏覽器的複雜性,适當的緩存設定非常重要。在本文中,我們介紹了以下最佳實踐:
- 盡可能多地緩存檔案,以便減少加載次數并改善性能。
- 盡可能使用 cache-control 定義緩存行為,尤其是對 IE。這降低了不同浏覽器之間的差别,是改善性能的最佳方法。
- 不要使用 “no settings related with cache”。
- 使用預設設定初次打開 IE 時,IE 浏覽器幾乎總是發送一個請求到伺服器端以檢索資料。
- 如果某個頁面不應該被緩存,則使用 “cache-control: no-cache, no-store” 來確定該頁面不會被緩存,尤其是當資料涉及安全或敏感資訊時。
- 除非必要,不要使用 post 請求,因為它不能被緩存。
參考資料
學習
- 檢視 HTTP Protocol Definition,了解基礎知識。
- 閱讀 IBM developerWorks Blogs 并加入讨論。
- “Notes.net 揭秘:改善 Web 站點的性能”介紹了 Web 性能改進。
- developerWorks 技術活動和網絡廣播:随時關注 developerWorks 技術活動和網絡廣播。
- developerWorks Web development 專區:通過專門關于 Web 技術的文章和教程,擴充您在網站開發方面的技能。
獲得産品和技術
- 開始使用 Apache Roller Weblogger 建構自己的部落格項目。
- 了解關于 IBM Mashup Center 的更多資訊并下載下傳免費試用版。