系列導航地址http://www.cnblogs.com/fzrain/p/3490137.htmlhtml
本文將使用一個開源框架CacheCow來實現針對Http請求資源緩存,本文主要介紹服務器端的緩存。ios
使用緩存技術能夠很好的提升Web Api的性能,減少服務器的開銷。咱們把這種緩存形式稱之爲:條件化請求(Conditional Requests)。具體表現爲:客戶端向服務器請求時會附加一個請求頭ETag,而後服務器會根據這個信息來決定是否須要把更新過的資源響應給客戶端,若是須要,則響應200狀態嗎以及資源內容,不然響應304狀態碼(Not modified)以及一個空的響應正文。git
寫了好多,那麼什麼是ETag呢?ETag是服務器爲特定資源生成的一個惟一標識(string類型)。你也能夠理解爲用來檢查服務器資源是否變化。github
ETag分2種類型:強類型和弱類型。對於弱類型的ETag包含一個前綴W(例如:W/53fsfsd322),而強類型的ETag不包含任何前綴(例如:53fsfsd322)。一般來講,弱類型ETag表明緩存短期資源(內存緩存),而強類型的ETag緩存是靠持久化的方式來實現的。web
先上一張圖:sql
由上圖可知:在一開始,客戶端發起一個Http Get請求,請求的是id爲4的course資源,因爲這個資源是第一次被訪問,所以服務器在把資源返回的同時附加了一個響應頭(ETag)。chrome
如今,客戶端發送Http Get請求想要再次請求相同的資源(Course id: 4),考慮到客戶端使用緩存,所以Get請求初始化的時候增長一個Header(If-None-Match),內容就是資源的ETag值。當服務器接受到請求的時候,就會讀取ETag的值並與服務器內的ETag值作比較,若是徹底相同,服務器就會返回304狀態碼(Not modified)而且正文不含任何內容。這樣客戶端就知道資源是最新的。數據庫
對於Http Get和Delete請求,咱們可使用(If-None-Match)頭,但對於更新時咱們要使用(If-Match)來匹配Put/Patch請求。請求到達的時候,服務器會校驗ETag值,若是不同,服務器就會響應一個412狀態碼(Precondition Failed),所以客戶端就知道本身的版本不是最新的,在客戶端沒有獲取最新資源以前是不容許更新的。api
通過了以前的一段簡單介紹,咱們來實現所謂的「條件化請求」。緩存
咱們須要使用NuGet來安裝CacheCow,打開NuGet控制檯,輸入「Install-Package CacheCow.Server -Version 0.4.12」。會安裝2個dll:CacheCow.Server和CacheCow.Common。
配置CacheCow也是很是簡單的,咱們所須要作的是建立一個Cache Handler並把它注入到web api的請求管道中。這個handler就是在請求到達和離開web api的時候檢查ETag和生成ETag的。
爲了實現這一點,在「WebApiConfig.cs」裏作以下配置:
//Configure HTTP Caching using Entity Tags (ETags) var cacheCowCacheHandler = new CacheCow.Server.CachingHandler(); config.MessageHandlers.Add(cacheCowCacheHandler);
到目前爲止,咱們的web api已經具備使用本機內存實現緩存的功能了,這也是CacheCow默認的配置,在單機狀態(只有一臺服務器)的時候可謂是比較完美了。然而,當應用程序走向分佈式的時候就出現爲題了——因爲不一樣的web服務器須要共享緩存狀態,所以咱們須要把緩存狀態持久化到一個單獨的地方(SQL Server, MongoDB, MemCache)。可是在實現持久化以前咱們先測試一下內存緩存。
打開咱們的測試客戶端PostMan(chrome插件),發送Get請求到:http://localhost:{your_port}/api/courses/4
結果:
請求註釋:
1.響應Http狀態碼是200,意昧着服務器把資源一塊兒響應過來了。
2.此次響應增長了2條頭信息:ETag和Last-Modified,目前咱們只需關心ETag的值,由於下次請求會用到。
3.ETag的類型是弱類型的(帶有W前綴),說明這個緩存存在於服務器的內存中,若是重啓IIS或切斷服務進程的話,緩存就會失效。
對於接受到ETag值的客戶端,在下次請求相同資源的時候就須要附加一個「If-None-Match」的請求頭,服務器就會比較客戶端與本身內存中的ETag值,若是相同,返回304(Not modified),不相同則返回200加上資源內容。
測試:咱們再次請求這個資源
結果:
對於此次請求來講:
1.http狀態碼是304,意味着客戶端的資源是最新的,所以響應body是空的
2.客戶端獲得相同的ETag值
在SQL Server中作緩存一樣很簡單,首先咱們要肯定在哪一個持久化介質中實現緩存,咱們用的是SQL Server,所以打開NuGet控制檯,輸入以下命令:Install-Package CacheCow.Server.EntityTagStore.SqlServer -Version 0.4.11。
而後在「WebApiConfig」作以下配置:
//Configure HTTP Caching using Entity Tags (ETags) var connString = System.Configuration.ConfigurationManager.ConnectionStrings["eLearningConnection"].ConnectionString; var eTagStore = new CacheCow.Server.EntityTagStore.SqlServer.SqlServerEntityTagStore(connString); var cacheCowCacheHandler = new CacheCow.Server.CachingHandler(eTagStore); cacheCowCacheHandler.AddLastModifiedHeader = false; config.MessageHandlers.Add(cacheCowCacheHandler);
上面的實現很明顯,CacheCow須要把緩存信息存到數據庫中,所以咱們須要制定咱們api所用的數據庫。而後把eTagStore實例賦給Cache handler。
若是你如今直接請求api的話,等待你的不是資源而是一個500錯誤碼。這是由於以前咱們介紹到CacheCow須要把緩存信息存入數據庫,那麼數據庫中就應該有一張對應的表以及操做這張表的存儲過程,所以咱們須要執行一個sql腳本。這個腳本一般在「{projectpath}\packages\CacheCow.Server.EntityTagStore.SqlServer.0.4.11\script」
執行完這個腳本後,你會發現數據庫多了一張表以及5個存儲過程:
ok,能夠測試了,仍是剛剛的例子:
正如上圖所示,ETag的值再也不是弱類型的了,所以咱們存到SQL Server中了,打開SQL Server中的CacheState表,你會發現:
如今,只要沒有客戶端來更新這個資源,以前訪問過這個資源的客戶端通通會獲得304狀態碼以及空的body(前提是客戶端的請求中包含ETag值,呵呵)。
如今咱們實現一下更新,客戶端要更新資源就須要包含一個「If-Match」的請求頭,以下圖所示:
結果:
ETag已經改變:
咱們使用老的ETag再次請求服務器:
因此結果:
這個響應告訴客戶端:」你手裏的資源不是最新的,先拿到最新的資源我才讓你修改」。
拖了很久的最後一篇終於和你們見面了,主要都是一些理論,代碼也就5行,不過感受ETag還真的挺強大的。
本次系列到這裏也要告一段落了,不過以後還打算介紹一些有其餘內容(包括Web Api 2的新特性IHttpActionResult,CORS的支持以及OData的支持等),敬請期待。。。