REST笔记(五):你应该知道的HTTP头------ETag
在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