ASP.NET 缓存技术(一)——启用页面输出缓存
作者寄語:MSDN 是最好的老師,互聯(lián)網(wǎng)是最智慧的生命體,分享是最重要的成長途徑,技術的進步在于學習、實踐和創(chuàng)新!
????? 本系列所講述的技術和展示的代碼適用于 .NET Framework 4.0 和 IIS7 下的 ASP.NET 4.0,所附示例代碼使用 Visual Studio 2010 開發(fā),并可能需要使用 SQL Express 服務。作者在學習 MSDN 和參考網(wǎng)絡文獻的基礎上對相關技術進行了歸納整理,如有不足和錯誤,歡迎大家指正。
為什么使用緩存技術?
????? 這可能是一個很好回答的問題,那就是為了提升應用程序的性能。但更多的人并不十分清楚應該在什么時候,怎樣去應用緩存技術。通常來說,一般的 ASP.NET 應用程序很少有人去關注緩存的使用,但是當這樣的應用程序因為需求的擴大,需要處理更多的數(shù)據(jù),需要承載更多的用戶,需要采用更復雜的部署時,普通的方法絕對會讓你對系統(tǒng)的性能表現(xiàn)感到束手無策。在現(xiàn)在內(nèi)存并不昂貴的時代,良好的緩存應用將會比優(yōu)化程序代碼為系統(tǒng)帶來的性能提升更為廉價。在這里提到了良好的緩存應用這種說法,因為緩存技術并不是萬能的,如何使用取決于系統(tǒng)的各種需求和指標。
ASP.NET 緩存技術中的兩個層面
????? 在 ASP.NET 的應用程序中,可以在頁面輸出和應用程序數(shù)據(jù)兩個層面應用緩存技術。
????? 對頁面輸出進行緩存是指在內(nèi)存中保存處理后的 ASP.NET 頁面。通常對 ASP.NET 頁面的請求都會導致 IIS7 經(jīng)歷如下過程:
??????
????? 當對頁面輸出進行緩存后,如果當前請求的頁面的服務器緩存已經(jīng)存在,則以上的執(zhí)行過程在“解析緩存”這一步完成后就會停止并返回緩存的頁面內(nèi)容,由此也導致了頁面的相關事件不會得到執(zhí)行,直到該頁面的服務器緩存失效。ASP.NET 為頁面輸出緩存提供了兩種服務器緩存模型,整頁緩存和部分頁緩存,而部分頁緩存又可采用兩種工作方式:控件緩存和緩存后替換。更為出色的是,ASP.NET 還可以根據(jù)請求參數(shù)的不同而創(chuàng)建同一頁面的不同緩存。更多關于頁面輸出的緩存將在后文詳細講述。
????? 對應用程序數(shù)據(jù)進行緩存是通過 ASP.NET 提供的一種編程方式來訪問可以是任意數(shù)據(jù)的鍵/值對,這些鍵/值對存儲在內(nèi)存中,使用方式與應用程序狀態(tài)(System.Web.HttpApplicationState)類似,只是它們是易失的。更多關于應用程序數(shù)據(jù)的緩存將在后文詳細講述。
開啟頁面輸出緩存
????? 通過在 ASPX 頁面文件中包含 @ OutputCache 指令,并設置它的 Duration 和 VaryByParam 屬性就可非常方便的啟用頁面輸出緩存。Duration 屬性用于指定頁面輸出緩存的緩存時間,以秒為單位;VaryByParam 屬性這里先設置為 none,有關它的更多信息將在后文講述。以下代碼演示了如何將頁面輸出內(nèi)容緩存 60 秒:
C# CODE?? :No Title Code| 1234 56789 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <%@ Page Language="C#" AutoEventWireup="true" %> <%@ OutputCache Duration="60" VaryByParam="none" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"><title></title> </head> <body><script runat="server">protected void Page_Load(object sender, EventArgs e){lblNowTime.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");}</script><form id="form1" runat="server"><div><asp:Label ID="lblNowTime" runat="server" /></div></form> </body> </html> |
????? 到這里,我們就已經(jīng)開啟了頁面輸出緩存,該段代碼中的 Page_Load 方法在每次執(zhí)行后,至少會過 60 秒才會再次執(zhí)行(為什么用了“至少”這個詞,結合后面的講述想想吧)。
頁面輸出緩存的本質
????? 在繼續(xù)深入之前,我們要先問問,頁面輸出緩存是怎樣實現(xiàn)的呢?頁面輸出緩存的定義可以這樣來說,在頁面的響應生命周期之內(nèi),將頁面的內(nèi)容存儲在可緩存設備上,在頁面過期之前,使用該存儲的內(nèi)容提供給用戶。可緩存設備包括發(fā)出請求的瀏覽器、響應請求的 Web 服務器以及在請求和響應流中其它任何具有緩存功能的設備,如代理服務器。在最基本的層面,HTTP 1.0 協(xié)議就已經(jīng)定義了簡單的緩存機制,現(xiàn)在流行的最新瀏覽器所支持的 HTTP 1.1 協(xié)議更是在這個基礎上進行了擴展并消除了 HTTP 1.0 協(xié)議的缺陷。
????? HTTP 協(xié)議通過在頭部添加 Cache-Control 標頭來控制頁面的緩存動作。HTTP 1.1 協(xié)議中的 Cache-Control 標頭有以下設置:
| 參數(shù) | 說明 |
| public | 數(shù)據(jù)內(nèi)容皆被儲存起來,就連有密碼保護的網(wǎng)頁也儲存,安全性很低。 |
| private | 數(shù)據(jù)內(nèi)容只能被儲存到私有的緩存中,通常是瀏覽器的本地緩存。這是 Cache-Control 標頭的默認值。 |
| no-cache | 數(shù)據(jù)內(nèi)容永遠不會被儲存,代理服務器和瀏覽器讀到此標頭就不會將數(shù)據(jù)內(nèi)容存入緩存。 |
| no-store | 數(shù)據(jù)內(nèi)容除不存入緩存中,也不能存入暫時的磁盤中,這個標頭防止敏感性數(shù)據(jù)被復制。 |
| must-revalidate | 用戶在每次讀取數(shù)據(jù)時,會再次和原來的服務器確定是否為最新數(shù)據(jù),而不是和中間的代理服務器。 |
| proxy-revalidate | 這個參數(shù)很像 must-revalidate,不過中間接收的代理服務器可以互相分享緩存。 |
| max-age=xxx | 數(shù)據(jù)內(nèi)容在 xxx 秒后失效,這個標頭就像 Exires 標頭(HTTP 1.0 協(xié)議定義的緩存過期機制)的功能一樣,不過 max-age=xxx 只能服務于支持 HTTP 1.1 協(xié)議的瀏覽器。假設兩者都有,max-age 優(yōu)先。 |
????? 通過 HTTP 協(xié)議控制頁面的緩存動作,通常可以像如下示例一樣添加 Cache-Control 標頭在響應流的頭部:
| HTTP 標頭 | 說明 |
| Cache-Control:max-age=3600 | 指示頁面應在 60 分鐘后過期,內(nèi)容不應在代理服務器上緩存。 |
| Cache-Control:no-cache | 指示頁面應每次向原來的服務器請求并獲取內(nèi)容。 |
| Cache-Control:public,max-age=3600 | 指示頁面應在 60 分鐘后過期,內(nèi)容可以在瀏覽器的本地區(qū)域和代理服務器上緩存。 |
????? 但是通過 Cache-Control 標頭的控制作用還取決于用戶不同的瀏覽方式:
????? (1)打開新窗口:如果 Cache-Control 的值為 private、no-cache、must-revalidate,那么打開新窗口訪問時都會重新訪問服務器。而如果指定了 max-age=xxx 值,則在 xxx 秒時間內(nèi)都不會重新訪問服務器。
????? (2)地址欄回車:如果 Cache-Control 的值為 private 或 must-revalidate,則只有第一次訪問時會訪問服務器,以后就不再訪問。如果值為 no-cache,那么每次都會訪問服務器。如果指定了 max-age,則在過期之前不會訪問服務器。
????? (3)按后退按鈕:如果 Cache-Control 的值為 private、must-revalidate、max-age,則不會重新訪問服務器。如果值為 no-cache,則每次都重新訪問服務器。
????? (4)按刷新按鈕:無論 Cache-Control 為何值,都會重新訪問服務器。
????? 通過 Cache-Control 標頭設置了緩存的頁面,再次向服務器請求時(比如按刷新按鈕),瀏覽器發(fā)出的請求頭部會添加 If-Modified-Since 標頭,該標頭向服務器詢問從指定的日期后該頁面是否已經(jīng)修改。對于 ASP.NET 而言,根據(jù)頁面是否開啟了服務器端緩存,響應這樣的請求會有兩種結果,一種是該頁面開啟了服務器端緩存并且該頁面緩存還未過期,則返回 304 的響應,這時瀏覽器使用本地緩存向用戶呈現(xiàn)頁面;其它情況則是重新處理該請求并啟動新的 ASP.NET 頁面生命周期,返回 200 的響應和新的頁面內(nèi)容。注意,請區(qū)別這里返回 304 響應的情況和前述的不會重新訪問服務器的情況的不同,后者根本就不向服務器發(fā)出請求。
????? 話題說到這里,我們已經(jīng)把基于 HTTP 協(xié)議實現(xiàn)的頁面緩存進行了說明,但 ASP.NET 同樣也給我們提供了服務器端的緩存,這種緩存前面多次提到。為了說明這點,我們先把 HTTP 協(xié)議實現(xiàn)的緩存放到一邊,就是說我們現(xiàn)在使用了 Cache-Control:no-cache 標頭來進行響應。當請求被 IIS 收到時,ASP.NET 會根據(jù)頁面的緩存設置來決定如何響應,如果頁面沒有設置服務器緩存,則接下來的事情大家都是知道的;如果頁面設置了服務器緩存并且緩存沒有過期,則返回 200 的響應和從服務器緩存中存儲的頁面內(nèi)容;如果頁面設置了服務器緩存但緩存已經(jīng)過期,則為該頁面啟動新的 ASP.NET 頁面生命周期進行處理,然后緩存新的頁面處理內(nèi)容并響應到客戶端。
????? 使用 ASP.NET 開發(fā)應用程序,我們完全可以結合由 HTTP 協(xié)議實現(xiàn)的緩存和 ASP.NET 自身提供的緩存,具體的應用當然就得看實際的情況了。
關于 @ OutputCache 指令
????? 對于 @ OutputCache 指令已經(jīng)介紹了 Duration 和 VaryByParam 屬性,與“頁面輸出緩存的本質”小節(jié)有關的屬性還有 Location 和 NoStore 屬性。NoStore 屬性接受一個布爾值,如果指定為 true,則向 Cache-Control 標頭添加 no-store 設置。Location 屬性接受 OutputCacheLocation 枚舉值之一,用于控制資源的輸出緩存 HTTP 響應的位置。
| 成員名稱 | 說明 |
| Any | 輸出緩存可位于產(chǎn)生請求的瀏覽器客戶端、參與請求的代理服務器(或任何其它服務器)或處理請求的服務器上。此值對應于 Cache-Control:public,并開啟服務器端緩存。 |
| Client | 輸出緩存位于產(chǎn)生請求的瀏覽器客戶端上。此值對應于 Cache-Control:private,并關閉服務器端緩存。 |
| Downstream | 輸出緩存可存儲在任何 HTTP 1.1 可緩存設備中,源服務器除外,這包括代理服務器和發(fā)出請求的客戶端。此值對應于 Cache-Control:public,并關閉服務器端緩存。 |
| Server | 輸出緩存位于處理請求的 Web 服務器上。此值對應于 Cache-Control:no-cache,并開啟服務器端緩存。 |
| None | 對于請求的頁面,禁用輸出緩存。此值對應于 Cache-Control:no-cache,并關閉服務器端緩存,這與在 ASPX 頁面上不包含 @ OutputCache 指令沒區(qū)別。 |
| ServerAndClient | 輸出緩存只能存儲在源服務器或發(fā)出請求的客戶端中,代理服務器不能緩存響應。此值對于 Cache-Control:private,并開啟服務器端緩存。 |
????? 現(xiàn)在針對 @ OutputCache 指令的基本設置已經(jīng)介紹完成了,有關它的更多控制細節(jié)將在下一講中闡述,現(xiàn)在我們已經(jīng)可以與“頁面輸出緩存的本質”小節(jié)中所講述的內(nèi)容結合起來,有效的控制頁面輸出緩存了,如果僅是應付一般的情況,到這樣就基本足夠了。
小結
?? ? ?本節(jié)初步揭開了 ASP.NET 緩存技術的面紗,介紹了開啟 ASPX 頁面輸出緩存的基本方法,但這不是本節(jié)的重點,最需要關注的是 ASP.NET 緩存技術的實現(xiàn)細節(jié),“頁面輸出緩存的本質”小節(jié)中對此有了說明,但限于篇幅和作者的水平,并不詳盡。大家可以多多實踐,并使用 Fiddler 這樣的 HTTP 嗅探工具來深入研究這些細節(jié)。
轉載于:https://www.cnblogs.com/xupeng/archive/2011/01/08/1931968.html
總結
以上是生活随笔為你收集整理的ASP.NET 缓存技术(一)——启用页面输出缓存的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《数学之美与浪潮之巅》读后感
- 下一篇: 让你认清楚JSP中的所有东西(java/