在HTTP1.1規范中,新增了一個HTTP頭信息:ETag。對Web開發者來說,它是一個非常重要的信息。它是用作緩存使
用的兩個主要的頭信息之一 (另一個是Expires)。除此之外,在REST架構中,它還可以用於控制並發操作(上節中已經大
致介紹AtomPub中控制並發的流程)。那么ETag是什么?它又幾種類型?強ETag與弱ETag之間有什么區別。?如何計算
ETag值?它與Last-Modified頭信息在使用上有什么區別?本節主要圍繞這幾個方面敘述一下自己的理解。
目錄:
- 什么是ETag?
- 計算ETag值
- ETag的類型以及他們之間的區別
- ETag與Last-Modified頭信息用途上的區別
什么是ETag?
ETag:是實體標簽(Entity Tag)的縮寫。ETag一般不以明文形式相應給客戶端。在資源的各個生命周期中,它都具有不
同的值,用於標識出資源的狀態。當資源發生變更時,如果其頭信息中一個或者多個發生變化,或者消息實體發生變化
,那么ETag也隨之發生變化。
ETag值的變更說明資源狀態已經被修改。往往可以通過時間戳就可以便宜的得到ETag頭信息。在服務端中如果發回給
消費者的相應從一開始起就由ETag控制,那么可以確保更細粒度的ETag升級完全由服務來進行控制。服務計算ETag值,
並在相應客戶端請求時將它返回給客戶端。
計算ETag值
在HTTP1.1協議中並沒有規范如何計算ETag。ETag值可以是唯一標識資源的任何東西,如持久化存儲中的某個資源關聯
的版本、一個或者多個文件屬性,實體頭信息和校驗值、(CheckSum),也可以計算實體信息的散列值。有時候,為了計
算一個ETag值可能有比較大的代價,此時可以采用生成唯一值等方式(如常見的GUID)。無論怎樣,服務都應該盡可能的
將ETag值返回給客戶端。客戶端不用關心ETag值如何產生,只要服務在資源狀態發生變更的情況下將ETag值發送給它就行
。下圖為MSDN中,OutgoingResponse類中設置ETag值的截圖:
從上圖可以看出,在REST架構下,ETag值可以通過Guid、整數、長整形、字符串四種類型的參數傳入SetETag方法,
WCF服務發回給客戶端的HTTP響應頭中就包含了ETag值。另外OutgoingResponse類也有字符串屬性:ETag直接給
它賦值也能在HTTP響應頭中寫入ETag值。
如下所示為使用文件屬性計算ETag:
public class ETag : IHeader { private string Value; public ETag(string value) { Value = value; WebOperationContext.Current.OutgoingResponse.ETag } #region IHeader 成員 public void AddHTTPHeader(ResponseContext context) { context.WriteHttpHeader(Value); } #endregion }
獲取ETag:
ETag eTag = new ETag(fileInfo.Name+fileInfo.LastWriteTimeUtc.ToString())
計算ETag值時,需要考慮兩個問題:計算與存儲。如果一個ETag值只需要很小的代價以及占用很低的存儲空間,那么
我們可以在每次需要發送給客戶端ETag值值的時候計算一遍就行行了。相反的,我們需要將之前就已經計算並存儲好
的ETag值發送給客戶端。之前說:將時間戳作為字符串作為一種廉價的方式來獲取ETag值。對於不是經常變化的消息,
它是一種足夠好的方案。注意:如果將時間戳做為ETag值,通常不應該用Last-Modified的值。由於HTTP機制中,所
以當我們在通過服務校驗資源狀態時,客戶端不需要進行相應的改動。計算ETag值開銷最大的一般是計算采用哈希算法
獲取資源的表述值。可以只計算資源的哈希值,也可以將頭信息和頭信息的值也包含進去。如果包含頭信息,那么注意
不要包含計算機標識的頭信息。同樣也應該避免包含Expires、Cache-Control和Vary頭信息。注意:在通過哈希算法
計算ETag值時,先要組裝資源的表述。若組裝也比較耗時,可以采用生成GUID的方式。優化ETag值的獲取。
ETag的類型以及他們之間的區別
ETag有兩種類型:強ETag(strong ETag)與弱ETag(weak ETag)。
強ETag表示形式:"22FAA065-2664-4197-9C5E-C92EA03D0A16"。
弱ETag表現形式:w/"22FAA065-2664-4197-9C5E-C92EA03D0A16"。
強、弱ETag類型的出現與Apache服務器計算ETag的方式有關。Apache默認通過FileEtag中FileEtag INode Mtime Siz
e的配置自動生成ETag(當然也可以通過用戶自定義的方式)。假設服務端的資源頻繁被修改(如1秒內修改了N次),此時
如果有用戶將Apache的配置改為MTime,由於MTime只能精確到秒,那么就可以避免強ETag在1秒內的ETag總是不同而
頻繁刷新Cache(如果資源在秒級經常被修改,也可以通過Last-Modified來解決)。
ETag與Last-Modified頭信息用途上的區別
按照HTTP標准,Last-Modified只能精確到秒級。ETag的出現可以很好的解決這個問題。在用途上,ETag常與
If-None-Match或者If-Match一起,由客戶端通過HTTP頭信息(包括ETag值)發送給服務端處理。ETag使用如下:
Get /Order/36 Http1.1
If-Match:"22FAA065-2664-4197-9C5E-C92EA03D0A16"
或If-None-Match:"22FAA065-2664-4197-9C5E-C92EA03D0A16"
Last-Modified常與If-Modified-Since一起由客戶端將Last-Modified值包括在HTTP頭信息中發給服務端進行處理。
其使用如下:
If-Modified-Since:Sat,24 Dec 2011 11:55:36 GMT