Asp.Net中MVC緩存詳解
本文通過(guò)介紹了Asp.Net中MVC緩存的種類,以及他們之間的區(qū)別等內(nèi)容,讓學(xué)習(xí)者能夠深入的了解MVC緩存的原理機(jī)制,以下是具體內(nèi)容:
緩存是一種保存資源副本并在下次請(qǐng)求時(shí)直接使用該副本的技術(shù)。當(dāng) web 緩存發(fā)現(xiàn)請(qǐng)求的資源已經(jīng)被存儲(chǔ),它會(huì)攔截請(qǐng)求,返回該資源的拷貝。
Web應(yīng)用緩存技術(shù)大體上可以分為兩類:服務(wù)端緩存和客戶端緩存。兩種目標(biāo)都是減少重復(fù)性內(nèi)容的生成和網(wǎng)絡(luò)傳輸工作,因?yàn)榫彺鏀?shù)據(jù)存儲(chǔ)的位置不同,而分為服務(wù)端緩存和客戶端緩存。
服務(wù)端緩存
服務(wù)端緩存技術(shù)關(guān)注于服務(wù)端數(shù)據(jù)查詢,生成或者操作技術(shù)。主要就是減少處理請(qǐng)求的工作量,減少數(shù)據(jù)庫(kù)查詢次數(shù)和生成HTML數(shù)據(jù)的CPU周期--減少每個(gè)bit的數(shù)據(jù)。
對(duì)于服務(wù)端緩存來(lái)說(shuō),不管是刷新頁(yè)面,重新輸入地址,還是Control+F5都不會(huì)規(guī)避緩存,如果緩存數(shù)據(jù)有效,一定是請(qǐng)求的緩存數(shù)據(jù)。
輸出緩存(Output Cache)
輸出緩存是Asp.Net下最常用的緩存機(jī)制。輸出緩存,緩存服務(wù)端生成的HTML數(shù)據(jù)--緩存Action下返回?cái)?shù)據(jù)(Html/Json)。這樣,在每次調(diào)用相同的Action時(shí),就不需要再次執(zhí)行Action方法。
緩存位置(Location)
OutputCache
使緩存的內(nèi)容一般放在三個(gè)位置上:服務(wù)端,代理服務(wù)器,瀏覽器客戶端。通過(guò)Loaction
屬性可以設(shè)置緩存的位置。
Loaction
屬性有如下值:
Any Client Downstream Server None ServerAndClient
默認(rèn)值為Any
,就是在三個(gè)位置都會(huì)緩存。但是應(yīng)該根據(jù)不同的情況使用不同的緩存位置。比如:要緩存的內(nèi)容是針對(duì)特定用戶的,每個(gè)用戶都會(huì)不同。這樣的話,該緩存就不能保存在服務(wù)器上。應(yīng)該保存在瀏覽器客戶端上。
使用Output Cache
在Controller
或者Action
上添加[OutputCache]
特性,使得被添加的Controller
或Action
可以緩存返回的數(shù)據(jù)。(在Action
添加會(huì)緩存當(dāng)前的Action
,在Controller
會(huì)緩存該Controller
下的所有Action
)
如下代碼:當(dāng)?shù)谝淮畏椒ㄔ揂ction時(shí),開始計(jì)時(shí)10秒,此10秒內(nèi)所有訪問(wèn)該Action的請(qǐng)求都會(huì)請(qǐng)求緩存數(shù)據(jù)。當(dāng)10秒結(jié)束后,再重新開始等待新一次請(qǐng)求,開始新的10秒緩存。就是每隔10秒丟掉舊緩存,等待新的請(qǐng)求,更新緩存數(shù)據(jù)。
using System.Web.Mvc; using System.Web.UI; namespace MvcApplication1.Controllers { public class HomeController : Controller { //緩存時(shí)間10秒,緩存變量為無(wú),緩存位置為服務(wù)端 [OutputCache(Duration=10, VaryByParam="none", Location = OutputCacheLocation.Server)] public ActionResult Index() { return View(); } } }
View:
@{ ViewBag.Title = "Index"; } <h2>Index</h2> <p>@DateTime.Now.ToString()</p>
點(diǎn)擊F12,查看請(qǐng)求
需要注意的是:
該緩存時(shí)間是絕對(duì)時(shí)間。此緩存是對(duì)所有訪問(wèn)該頁(yè)面的用戶都有效。不能保證緩存一定有效。當(dāng)內(nèi)存資源不夠時(shí),緩存就會(huì)自動(dòng)地將沒(méi)用的或者優(yōu)先級(jí)低緩存清除。
客戶端緩存
除了服務(wù)端緩存外,客戶端也可以緩存數(shù)據(jù)。它避免了向服務(wù)器重復(fù)提交獲取重復(fù)數(shù)據(jù)的請(qǐng)求,把一些重復(fù)數(shù)據(jù)緩存到本地。服務(wù)端緩存是為了更快的處理客戶端請(qǐng)求,而客戶端緩存則是為了避免不必要的請(qǐng)求。
(瀏覽器會(huì)自動(dòng)把靜態(tài)資源緩存到瀏覽器)
MVC中指定Location
值為OutputCacheLocation.Client
使緩存在瀏覽器客戶端上。
using System.Web.Mvc; using System.Web.UI; namespace MvcApplication1.Controllers { public class BadUserController : Controller { //緩存時(shí)間為10秒,緩存參數(shù)為無(wú),緩存位置為客戶端 [OutputCache(Duration = 10, VaryByParam = "none",Location = OutputCacheLocation.Client)] public ActionResult ClientCache() { return View(); } } }
@{ ViewBag.Title = "ClientCache"; } <h2>ClientCache</h2> <p>@DateTime.Now.ToString()</p>
客戶端緩存和服務(wù)端緩存不一樣。
刷新,重新輸入地址,和Control+F5都有可能破壞客戶端緩存,從服務(wù)端重新獲取數(shù)據(jù)。
瀏覽器刷新,和重新輸入地址會(huì)避免請(qǐng)求該URL頁(yè)面的客戶端緩存,只避免請(qǐng)求該URL頁(yè)面的緩存。(如果該頁(yè)面有其他URL是被客戶端緩存的,這些資源或頁(yè)面的緩存不會(huì)被避免)。
那么什么情況下客戶端緩存才有效?
通過(guò)URL訪問(wèn),客戶端緩存才有效。
比如:
頁(yè)面A是客戶端緩存,同時(shí)頁(yè)面A有一個(gè)跳向頁(yè)面B的鏈接。通過(guò)A到達(dá)頁(yè)面B,同時(shí)頁(yè)面B也有一個(gè)鏈接,這個(gè)鏈接跳向A。通過(guò)B再次訪問(wèn)A,此時(shí)頁(yè)面A獲取的數(shù)據(jù)就是客戶端的緩存數(shù)據(jù),并沒(méi)有請(qǐng)求服務(wù)端,是沒(méi)有請(qǐng)求服務(wù)端。不是304,status-code依然是200。 Status-Code:304/200(from cache)
304
只有當(dāng)客戶端和服務(wù)端同時(shí)都緩存了數(shù)據(jù)。且緩存沒(méi)有更新的時(shí)候,才會(huì)有304。即這個(gè)緩存是要到服務(wù)端驗(yàn)證(根據(jù)ETag和If-Modify-Since),該緩存是否最新。如果要更新緩存,從服務(wù)端獲取數(shù)據(jù),status code:200,否則status code:304.
304 和200(from cache)區(qū)別
304是會(huì)到服務(wù)端去校驗(yàn)一次當(dāng)前客戶端緩存是否有效(根據(jù)ETag和If-Modify-Since)。而200(from cache)則沒(méi)有向服務(wù)端校驗(yàn),也沒(méi)有向服務(wù)端請(qǐng)求,直接使用了客戶端緩存。
有時(shí)我們又需要避免這種沒(méi)有向服務(wù)端請(qǐng)求,直接使用緩存的情況。解決辦法就是更改這個(gè)緩存的url,添加一個(gè)版本號(hào)或唯一值。這樣因?yàn)閡rl的更改使得在客戶端沒(méi)有對(duì)應(yīng)的url緩存,就會(huì)從服務(wù)端重新獲取,再緩存該URL的數(shù)據(jù)。
不同內(nèi)容的輸出緩存
之前的緩存都是Action返回相同的內(nèi)容。如果Action每次返回的內(nèi)容不同,那又該怎么緩存這些不同的內(nèi)容呢?
使用OutputCache
特性的VaryByParam
屬性來(lái)解決這個(gè)問(wèn)題。當(dāng)表單參數(shù)或查詢字符串參數(shù)變化時(shí),該屬性能夠創(chuàng)建同一個(gè)Action下不同的緩存。
如下代碼:Master 獲取列表。Details 獲取列表中選擇項(xiàng)的詳細(xì)內(nèi)容。通過(guò)使用VaryByParam
來(lái)緩存不同的id
的列表項(xiàng)的詳細(xì)內(nèi)容。
using System.Web.Mvc; namespace MvcApplication1.Controllers { public class MoviesController : Controller { public MoviesController() { } [OutputCache(Duration=int.MaxValue, VaryByParam="none")] public ActionResult Master() { //獲取列表 return View(); } [OutputCache(Duration = int.MaxValue, VaryByParam = "id")] public ActionResult Details(int id) { //根據(jù)參數(shù)id,從數(shù)據(jù)庫(kù)中獲取指定詳細(xì)內(nèi)容,并緩存該內(nèi)容。不同的id會(huì)得到不同的內(nèi)容,自然也會(huì)有緩存。 //但是如果設(shè)置VaryByParam="none"那么不管id是多少,都直接從緩存中獲取數(shù)據(jù),不執(zhí)行該Action,這樣就會(huì)只返回第一次選擇項(xiàng)的數(shù)據(jù)。 return View(); } } }
Details()
操作包括一個(gè)帶有值“Id”的VaryByParam
屬性。當(dāng)將Id參數(shù)的不同值傳遞給控制器操作時(shí),將生成不同的緩存內(nèi)容。
VaryByParam
可以根據(jù)參數(shù)緩存不同的內(nèi)容
當(dāng)VaryByParam="*"
: 每當(dāng)表單或查詢字符串參數(shù)變化時(shí),創(chuàng)建一個(gè)不同的緩存版本。當(dāng)VaryByParam="none"
: 不創(chuàng)建不同的緩存內(nèi)容,不根據(jù)參數(shù)緩存不同的內(nèi)容,即只有一個(gè)內(nèi)容的緩存。當(dāng)VaryByParam="參數(shù)列表"
: 為不同的參數(shù)創(chuàng)建不同的緩存版本。
緩存配置
除了在OutputCache
特性上直接配置緩存策略,可以在web.config
文件中使用緩存配置文件,同一管理緩存的策略。使用配置文件相比直接使用屬性有如下幾點(diǎn)好處:
可以實(shí)現(xiàn)一次定義,多處使用。
可以修改web配置文件,而無(wú)需重新編譯應(yīng)用程序。(如果想把已經(jīng)部署到生產(chǎn)環(huán)境中的應(yīng)用程序禁用緩存,可以修改web配置文件中定義的緩存配置。對(duì)web配置文件的任何更改都將被自動(dòng)檢測(cè)并應(yīng)用。)
例如,web.config部分定義了一個(gè)名為“cache1Hour”的緩存配置文件。使用該配置項(xiàng)時(shí),只需指定CacheProfile=配置項(xiàng)名稱即可。
<caching> <outputCacheSettings> <outputCacheProfiles> <add name="Cache1Hour" duration="3600" varyByParam="none"/> </outputCacheProfiles> </outputCacheSettings> </caching>
using System; using System.Web.Mvc; namespace MvcApplication1.Controllers { public class ProfileController : Controller { //配置文件中的緩存策略名稱賦值給CacheProfile [OutputCache(CacheProfile="Cache1Hour")] public string Index() { return DateTime.Now.ToString(); } } }
簡(jiǎn)單介紹下Http緩存的頭相關(guān)信息:
消息頭 | 值 | 類型 | 說(shuō)明 |
---|---|---|---|
Expires | Thu, 30 Nov 2017 08:21:14 GMT | 響應(yīng) | 過(guò)期時(shí)間,為格林威治時(shí)間 (GMT) |
Pragma | no-cache | 響應(yīng) | 忽略瀏覽器緩存(Http1.1用Cache-Control代替) |
Cache-Control | no-cache | 請(qǐng)求/響應(yīng) | 客戶端緩存驗(yàn)證 |
Cache-Control | no-store | 請(qǐng)求/響應(yīng) | 不在任何地方保存數(shù)據(jù),不允許被緩存 |
Cache-Control | max-age=[秒] | 請(qǐng)求/響應(yīng) | 設(shè)置瀏覽器緩存最長(zhǎng)時(shí)間 |
Cache-Control | public | 響應(yīng) | 緩存在任何地方 |
Cache-Control | private | 響應(yīng) | 緩存該用戶的瀏覽器 |
Last-Modified | Thu, 30 Nov 2017 08:21:14 GMT | 響應(yīng) | 告訴瀏覽器服務(wù)端最后一次修改的時(shí)間 |
If-Modified-Since | Thu, 30 Nov 2017 08:21:14 GMT | 請(qǐng)求 | 如果瀏覽器中Last-Modofied有值,在請(qǐng)求中把值給If-Modified-Since,提交給服務(wù)端 |
ETag | 3df04c15b968d31:0 | 響應(yīng) | 該資源及其版本在服務(wù)端的唯一標(biāo)識(shí) |
If-None-Match | 3df04c15b968d31:0 | 請(qǐng)求 | 把上次請(qǐng)求中獲取到的ETag值,賦值給If-None-Match并提交給服務(wù)端 |
Vary | Accept-Encoding | 響應(yīng) | 從多個(gè)緩存副本中選擇匹配的版本 |
有幾個(gè)容易理解錯(cuò)誤的點(diǎn)
no-cache: 使用no-cache 指令的目的是為了防止從緩存中使用過(guò)期的資源,所以每次使用緩存時(shí)都要到服務(wù)端去驗(yàn)證。從字面意思上很容易把no-cache誤解成為不緩存,但事實(shí)上no-cache代表不緩存過(guò)期的資源,緩存會(huì)向源服務(wù)器進(jìn)行有效期確認(rèn)后處理資源。
no-store: 不存儲(chǔ)客戶端相關(guān)請(qǐng)求或服務(wù)器響應(yīng)的任何內(nèi)容,即真正的不緩存。
- 如何在ASP.Net Core使用分布式緩存的實(shí)現(xiàn)
- Asp.net Core 3.1基于AspectCore實(shí)現(xiàn)AOP實(shí)現(xiàn)事務(wù)、緩存攔截器功能
- .NetCore之接口緩存的實(shí)現(xiàn)示例
- ASP.NET Core中的Http緩存使用
- .NET Core系列之MemoryCache 緩存域
- .NET Core系列之MemoryCache 緩存選項(xiàng)
- .NET Core系列之MemoryCache 緩存過(guò)期
- 詳解Asp.Net Core 2.1+的視圖緩存(響應(yīng)緩存)
- ASP.NET Core緩存靜態(tài)資源示例詳解
- 詳解.Net緩存之MemoryCahe
相關(guān)文章
.NET操作NPOI實(shí)現(xiàn)Excel的導(dǎo)入導(dǎo)出
NPOI是指構(gòu)建在POI 3.x版本之上的一個(gè)程序,NPOI可以在沒(méi)有安裝Office的情況下對(duì)Word或Excel文檔進(jìn)行讀寫操作,下面小編為大家介紹了如何操作NPOI實(shí)現(xiàn)Excel的導(dǎo)入導(dǎo)出,需要的可以參考一下2023-09-09C# PaddleDetection yolo實(shí)現(xiàn)印章檢測(cè)
這篇文章主要為大家詳細(xì)介紹了C#如何結(jié)合PaddleDetection yolo實(shí)現(xiàn)印章檢測(cè),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-11-11C#實(shí)現(xiàn)多線程寫入同一個(gè)文件的方法
這篇文章主要介紹了C#實(shí)現(xiàn)多線程寫入同一個(gè)文件的方法,涉及C#多線程操作文件讀寫的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-08-08C#3.0使用EventLog類寫Windows事件日志的方法
這篇文章主要介紹了C#3.0使用EventLog類寫Windows事件日志的方法,以簡(jiǎn)單實(shí)例形式分析了C#寫windows事件日志的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-08-08