[WCF REST] 提高性能的一個有效的手段:條件資源獲取(Conditional...

2021-01-11 開源中國

條件獲取(Conditional Retrieval)旨在解決這樣的問題:客戶端獲取某個資源並對其進行緩存,當再次獲取相同資源時,如果資源數據與之前獲取的一致,則不再返回真正的資源數據,而是在回覆中設置一個「標識」表明獲取的資源並未發生改變。[原始碼從這裡下載]

一、 HTTP對條件獲取的支持

HTTP對條件獲取提供了原生的支持。具體的實現是這樣的:服務端接收到客戶端針對某個資源的第一次獲取請求時,除了將資源數據作為HTTP回復主體返回之外,還會設置一個叫做ETag的回覆報頭。這個ETag與資源本身關聯並且可以對資源進行對等性判斷,比如我們可以將資源內容的哈希碼作為這個ETag報頭。

客戶端接收到資源後對其進行緩存,並從回覆中獲取到這個ETag報頭值。當再次對相同的資源進行請求時,它會為HTTP請求添加一個名為If-None-Match報頭,而該報頭的值就是這個緩存的ETag值。服務端接收到該請求之後會通過If-None-Match請求報頭確認最新的資源數據是否與該報頭值代表的數據一致,如果一致則回復一個狀態為「304 (Not Modified)」的空消息,否則將新的資源置於回復消息的主體並附上基於新資源數據的ETag報頭。

除此之外,條件獲取還支持另一種基於「最近修改時間」的資源改變判斷機制。這種機制也很簡單:服務端記錄下資源最近一次修改的時間,並被作為客戶端第一次訪問請求的ETag回復報頭。客戶端針對相同資源的後續請求會將此ETag表示的時間作為一個名為If-Modified-Since的報頭,而服務端則將該報頭的時間和資源最近一次修改的時間進行比較從而確定請求的資源是否被改變。如果資源尚未改變則同樣回復以狀態為「304 (Not Modified)」的空消息,否則將新的資源置於回復消息的主體並附上新的ETag報頭。條件獲取僅僅針對方法類型為GET和HEAD的HTTP請求。

二、 WebOperationContext與條件獲取

對於Web HTTP編程模型來說,通過當前WebOperationContext可以很容易地進行條件獲取的檢測和相相關HTTP報頭的設置和獲取。具體來說,服務端通過表示入棧請求上下文的IncomingWebRequestContext對象的CheckConditionalRetrieve方法進行條件獲取的檢測。其中參數類型為DateTime的重載用採用「最近修改時間」的資源改變判斷機制。如果確資源尚未改變,則直接拋出一個HTTP狀態為NotModified的WebFaultException,並將lastModified參數表示的時間作為回復消息的ETag報頭。

對於其他的4個CheckConditionalRetrieve方法,作為參數的entityTag(ETag)將與請求消息的If-None-Match進行比較,如果不一致也會拋出HTTP狀態為NotModified的WebFaultException,並將該參數值作為回復消息的ETag報頭。

1: public class IncomingWebRequestContext

2: {

3: //其他成員

4: public void CheckConditionalRetrieve(DateTime lastModified);

5: 

6: public void CheckConditionalRetrieve(Guid entityTag);

7: public void CheckConditionalRetrieve(int entityTag);

8: public void CheckConditionalRetrieve(long entityTag);

9: public void CheckConditionalRetrieve(string entityTag);

10: 

11: public DateTime? IfModifiedSince { get; }

12: public IEnumerable<string> IfNoneMatch { get; }

13: }

IncomingWebRequestContext還具有IfModifiedSince和IfNoneMatch這兩個只讀屬性,它們分別返回請求消息的If-Modified-Since和If-None-Match報頭。而服務端針對回復消息的ETag報頭的設置可以通過OutgoingWebResponseContext的四個SetETag方法來完成。

1: public class OutgoingWebResponseContext

2: {

3: //其他成員

4: public void SetETag(Guid entityTag);

5: public void SetETag(int entityTag);

6: public void SetETag(long entityTag);

7: public void SetETag(string entityTag);

8: }

對於客戶端來說,它可以通過當前WebOperationContext的IncomingResponse屬性得到表示入棧回復上下文的IncomingWebResponseContext對象,並通過其只讀屬性ETag獲取當前HTTP回復的ETag報頭。

1: public class IncomingWebResponseContext

2: {

3: //其他成員

4: public string ETag { get; }

5: }

如果客戶端需要為請求設置If-Modified-Since和If-None-Match報頭,則可以通過當前WebOperationContext的OutgoingRequest屬性得到表示出棧請求上下文的OutgoingWebRequestContext對象,然後分別設置IfModifiedSince和IfNoneMatch屬性即可。

1: public class OutgoingWebRequestContext

2: {

3: //其他成員

4: public string IfModifiedSince { get; set; }

5: public string IfNoneMatch { get; set; }

6: }

需要注意的是,如果採用WCF客戶端進行服務調用,一旦接收到狀態為「304(Not Modified)」的回覆會拋出如下圖所示的ProtocolException異常,並提示「遠程伺服器返回了意外響應: (304) Not Modified」。

三、實例演示:創建基於條件獲取的REST服務

接下來我們按照條件獲取的方式來改造之前演示的用於管理員工信息的EmployeesService。假設我們的員工數量比較多,用於獲取所有員工列表的GetAll操作將會返回一個龐大的數據。如果客戶端對第一次獲取到的員工列表進行緩存,那麼對有後續針對GetAll操作的請求,在員工信息沒有任何改變的情況下服務端只需要回復一個狀態為304(Not Modified)的HTTP消息即可。

為此我們對EmployeesService的GetAll操作方法進行了如下的改造:我們通過當前WebOperationContext得到表示入棧請求上下文的IncomingWebRequestContext對象,並調用其CheckConditionalRetrieve進行條件獲取檢驗,而傳入的參數是最新員工列表對象的哈希碼。在返回員工列表之前我們將此哈希碼作為了回復消息的ETag報頭。

1: public class EmployeesService : IEmployees

2: {

3: //其他成員

4: private static IList<Employee> employees = new List<Employee>

5: {

6: new Employee{ Id = "001", Name="張三", Department="開發部", Grade = "G7"},

7: new Employee{ Id = "002", Name="李四", Department="人事部", Grade = "G6"}

8: };

9: public IEnumerable<Employee> GetAll()

10: {

11: int hashCode = employees.GetHashCode();

12: WebOperationContext.Current.IncomingRequest.CheckConditionalRetrieve(hashCode);

13: WebOperationContext.Current.OutgoingResponse.SetETag(hashCode);

14: return employees;

15: }

16: }

我們通過手工發送HTTP請求的方式來調用EmployeesService的GetAll操作,為此我們創建了如下一個GetAllEmployees方法。該方法的參數ifNoneMatch和eTag分別表示請求消息的If-None-Match報頭和回復消息的ETag報頭。我們通過調用HttpWebRequest的靜態方法Create基於服務操作地址創建一個HttpWebRequest對象,並設置該請求的If-None-Match報頭的HTTP方法(GET)。

我們通過調用HttpWebRequest對象的GetResponse發送請求並得到回覆,在列印回復內容之前我們獲取了回復的ETag報頭。在回復狀態為「304 (Not Modified)」的情況下,GetResponse方法會 拋出一個WebException異常,所以我們對該類型的異常進行的捕獲。如果WebException異常的StatusCode屬性返回的HTTP狀態是我們預知的NotModified,則意味著獲取的員工列表未曾改變,於是我們在控制臺上列印「服務端數據未發生變化」字樣。

1: static void GetAllEmployees(string ifNoneMatch, out string eTag)

2: {

3: eTag = ifNoneMatch;

4: Uri address = new Uri("http://127.0.0.1:3721/employees/all");

5: var request = (HttpWebRequest)HttpWebRequest.Create(address);

6: if (!string.IsNullOrEmpty(ifNoneMatch))

7: {

8: request.Headers.Add(HttpRequestHeader.IfNoneMatch, ifNoneMatch);

9: }

10: request.Method = "GET";

11: try

12: {

13: var response = (HttpWebResponse)request.GetResponse();

14: eTag = response.Headers[HttpResponseHeader.ETag];

15: using(StreamReader reader =

16: new StreamReader(response.GetResponseStream(), Encoding.UTF8))

17: {

18: Console.WriteLine(reader.ReadToEnd() + Environment.NewLine);

19: }

20: }

21: catch (WebException ex)

22: {

23: HttpWebResponse response = ex.Response as HttpWebResponse;

24: if (null == response)

25: {

26: throw;

27: }

28: if (response.StatusCode == HttpStatusCode.NotModified)

29: {

30: Console.WriteLine("服務端數據未發生變化");

31: return;

32: }

33: throw;

34: }

35: }

然後我們通過如下的代碼調用上面定義的GetAllEmployees方法進行兩次服務調用,並將第一次調用返回的ETag報頭作為第二次調用的If-None-Match報頭。

1: string etag;

2: Console.WriteLine("第1次服務調用:");

3: GetAllEmployees("", out etag);

4: Console.WriteLine("第2次服務調用:");

5: GetAllEmployees(etag, out etag);

6: Console.Read();

在服務成功寄宿的情況下調用這段程序會在控制臺上輸出如下的結果,從中我們可以看到員工列表數據只在第1次服務調用中返回。

1: 第1次服務調用:

2: <ArrayOfEmployee xmlns="http://www.artech.com/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Employee><Department>開發部</Department><Grade>G7</Grade><Id>001</Id><Name>張三</Name></Employee><Employee><Department>人事部</Department><Grade>G6</Grade><Id>002</Id><Name>李四</Name></Employee></ArrayOfEmployee>

3: 

4: 第2次服務調用:

5: 服務端數據未發生變化

原文連結:

http://www.cnblogs.com/artech/archive/2012/02/13/wcf-rest-conditional-retrieval.html

相關焦點

  • Real conditionals 真實條件句
    一分鐘英語Real conditionals 真實條件句內容簡介你知道如何在日常對話中使用真實條件句嗎?「If」 引導的真實條件句應該使用在什麼場景中?「一分鐘英語」 將語法點化繁為簡。Today we're going to look at how we can make conditional sentences easy.So let's start with a real conditional, something like "If it rains tomorrow, I'll bring an umbrella".
  • 硬核語法- 第三條件句 Third Conditional Sentences
    Today we are going to dive deep on some awesome grammar, the third conditional.因此,我知道你肯定會喜歡今天的課程的。今天,我們將深入探討一個超讚的語法現象,第三條件句。
  • 第一、第二條件句練習 First or Second Conditional
    And the things that are different about these five types of conditional sentences relate to time and also to verb tense.有一個「if」子句和一個主句。這五種類型條件句的不同之處是時間以及動詞時態。
  • 如何使用零條件句和第一條件句 Conditional Sentences
    這類語法課聽起來可能很嚴肅,但是學會有效地使用條件句將幫助你清楚地表達自我,並且以一種真正有創造性的方式使用英語。條件句真的很常見,英語母語者會一直使用它們,所以如果你開始注意的話,你在閱讀的時候肯定會注意到這個句子結構,在聽東西的時候甚至會聽到更多。
  • 提高聚氨酯樹脂性能的有效方法
    以皮革塗飾劑為例:塗飾是皮革製造過程中的一個重要環節。它可增加皮革的美觀和耐用性能,提高檔次,增加花色品種、擴大使用範圍。其中聚氨酯類塗飾劑的成膜性能好、遮蓋力強、粘結牢固,塗層的物理性能優異,可大大提高成革的等級,為此受到高度重視和廣泛的關注。
  • 通過Kettle調用Rest API獲取信息
    在雲計算環境中,運維人員可以通過調用這些Rest API,獲取Open Stack環境的服務拓撲、主機、虛擬機的基本信息。這個過程,一般需要一個完整的開發環境以及代碼的書寫,本文主要介紹利用ETL工具Kettle來實現Rest API的調用和存儲過程,取得Open Stack環境拓撲信息,以達到與開發代碼同等的效果。
  • 關於WCF、WebAPI、WCFREST、WebService之間的區別理解
    在.Net平臺下,有大量的技術讓你創建一個HTTP服務,像Web Service,WCF,現在又出了Web API。在.Net平臺下,你有很多的選擇來構建一個HTTP Services。我分享一下我對Web Service、WCF以及Web API的理解。
  • 英語語法中的條件句
    Generally, conditional sentences are often divided into different types. 條件句是由兩個從句組成的句子,一個是if從句,另一個是main從句。一般來說,條件句通常分為不同的類型。
  • 如何在Keras中自定義機器學習性能指標
    Keras提供的指標使得我們能夠評估深度學習模型的性能。由於Keras提供了大量指標,因此為生產模型選擇理想指標是一項複雜的工作。在某些情況下,您可能必須自定義指標(因為Keras根本無法提供所需的指標),這會影響模型的最終性能。
  • 留學英語作業寫作之條件從句用法
    條件從句是比較advanced的英語語法點。通常條件句分為真實條件句和虛擬條件句。前者要使用直接陳述的方式表達,後者則要使用虛擬語氣。一般來說,當一個從句所表達的條件是有可能實現的、有可能是真實的條件時,用真實條件句;如果一個從句所表達的條件是不可能實現的、與客觀事實完全相反的條件時,則使用虛擬條件句。
  • 行波磁場大幅提高ZL205A合金性能
    通過改進鑄造工藝使其在航空工業等結構件上應用,但仍缺乏有效的手段控制其凝固過程。電磁場可以通過超距離作用將熱和力施加在熔體上,可以改變材料的生長取向和熔體的運動方式進而改善材料的組織性能或優化成形工藝過程,被廣泛地應用在材料製備和成形過程中。
  • 川大姚亞東教授團隊CC報導丨有機陰離子插層的氫氧化鈷的無定形化:OER性能顯著提高
    近年來,層狀過渡金屬氫氧化物(LTMHs)被不斷探索,研究者們通過各種調控手段實現了LTMHs的電催化性能的不斷提升。其中,陰離子插層是一種簡單有效的手段,它利用LTMHs的層間離子可交換性,將具有大分子鏈的有機陰離子插入層間,擴大其層間距,提高電催化活性。
  • 李永舫&張佔軍:低沸點、低成本添加劑DFB有效提高OSC的性能
    近年來,由於ITIC、Y6等低帶隙小分子受體和帶隙共軛聚合物給體以及PM6、J71、PTQ10等聚合物給體的發展,有機電致發光材料的光電轉換效率(PCE)有了很大的提高。除了新的光伏材料外,研究人員還開發了一些器件優化策略來改善OSCs的PCE,如溶劑添加劑處理和熱退火。
  • 李永舫&張佔軍:低沸點、低成本添加劑DFB有效提高OSC的性能
    近年來,由於ITIC、Y6等低帶隙小分子受體和帶隙共軛聚合物給體以及PM6、J71、PTQ10等聚合物給體的發展,有機電致發光材料的光電轉換效率(PCE)有了很大的提高。除了新的光伏材料外,研究人員還開發了一些器件優化策略來改善OSCs的PCE,如溶劑添加劑處理和熱退火。
  • 《石器時代M》轉生資源怎麼得 轉生資源獲取大全
    導 讀 石器時代M轉生資源怎麼獲取?轉生資源獲取大全。
  • 有效傳播能力:提高文化軟實力的重要環節
    新聞媒體的有效傳播能力如何,直接影響一國的新聞信息、價值理念、文化產品等在國際範圍內傳播的廣度、深度和效果。因此,新聞媒體的有效傳播能力是國家文化軟實力的重要組成部分。增強新聞媒體的有效傳播能力,就成為提高國家文化軟實力的一個重要環節。
  • 輻射避難所OL資源獲取指南 資源獲取技巧
    今天為大家帶來的是輻射避難所OL資源獲取指南,資源獲取技巧。這裡匯總了遊戲中資源獲取的相關技巧,感興趣的小夥伴一起來看看吧。
  • 計量經濟學中的「條件」與「無條件」
    發生情況下, 發生的條件概率。在實踐中,究竟應該使用(無條件)概率還是條件概率呢?看一個簡單例子就能明白。 只是一個常數,也就是 「無條件期望」(unconditional probability)。如果理解了條件分布,那麼條件期望就容易理解了。
  • 光催化之提高半導體材料光解水產氫的有效途徑 — 「摻雜」
    本期內容就來聊聊光催化分解水產氫的基本原理,然後結合上期「提高半導體材料光催化活性的有效途徑」內容之一體相摻雜是如何來介紹提高半導體材料光解水產氫的有效途徑。目前對半導體材料進行陰陽離子摻雜是調控能帶結構最有效的方法之一。經實驗證實,摻雜不僅可以減小半導體能帶的大小,還能在半導體內部形成一個新的能級結構,可以有效的減少光生載流子的複合機率。目前,陽離子的摻雜對半導體能帶的調控主要是一些稀土元素或過渡金屬元素。
  • 有效社交資源互補
    其實愛因斯坦的相對論力學和牛頓的經典力學不是一個理論體系,可都是力學,一個是曲面的一個是平面的,會解偏微分方程就容易理解。人也是一樣,生物學特徵相同,可思想迥異,每個人都由於受教育程度不同,生活環境不同,人的價值取向不同,個體差異是相當大的,最簡單的如中小學教師,在一個單位可能差不多,可不在一起差異巨大,去民辦學校或科研機構打工,貨幣差距就可能幾倍十倍啊,我常聽人講我也是老師,好象老師就沒差異,不信你去全國一流的民辦學校試試,你拿到什麼檔次的薪水?就知道你的斤兩了。