什么是ETag

 

ETag 是 Entity Tag 的缩写,中文译过来就是实体标签的意思。在HTTP1.1协议中其实就是请求HEAD中的一个属性而已。

HTTP/1.1 200 OK
Date: Mon, 23 May 2005 22:38:34 GMT
Content-Type: text/html; charset=UTF-8
Content-Encoding: UTF-8
Content-Length: 138
Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT
Server: Apache/1.3.3.7 (Unix) (Red-Hat/Linux)
ETag: "3f80f-1b6-3e1cb03b"
Accept-Ranges: bytes
Connection: close

<html>
<head>
  <title>An Example Page</title>
</head>
<body>
  Hello World, this is a very simple HTML document.
</body>
</html>

请注意第8行的 ETag: "3f80f-1b6-3e1cb03b"配置,那么为什么要用ETag呢?

ETag是HTTP1.1中才加入的一个属性,用来帮助服务器控制Web端的缓存验证。它的原理是这样的,当浏览器请求服务器的某项资源(A)时, 服务器根据A算出一个哈希值(3f80f-1b6-3e1cb03b)并通过 ETag 返回给浏览器,浏览器把"3f80f-1b6-3e1cb03b" 和 A 同时缓存在本地,当下次再次向服务器请求A时,会通过类似 If-None-Match: "3f80f-1b6-3e1cb03b" 的请求头把ETag发送给服务器,服务器再次计算A的哈希值并和浏览器返回的值做比较,如果发现A发生了变化就把A返回给浏览器(200),如果发现A没有变化就给浏览器返回一个304未修改。这样通过控制浏览器端的缓存,可以节省服务器的带宽,因为服务器不需要每次都把全量数据返回给客户端。

注:HTTP中并没有指定如何生成ETag,哈希是比较理想的选择。

通常情况下,ETag更类似于资源指纹(fingerprints),如果资源发生变化了就会生成一个新的指纹,这样可以快速的比较资源的变化。在服务器端实现中,很多情况下并不会用哈希来计算ETag,这会严重浪费服务器端资源,很多网站默认是禁用ETag的。有些情况下,可以把ETag退化,比如通过资源的版本或者修改时间来生成ETag。

如果通过资源修改时间来生成ETag,那么效果和HTTP协议里面的另外一个控制属性(Last-Modified)就雷同了,使用 Last-Modified 的问题在于它的精度在秒(s)的级别,比较适合不太敏感的静态资源。

后记

在友盟的时候做过一个项目 - 在线参数,这个功能在很多游戏类App中非常流行,也有很多App会通过它来控制内置广告的开关,曾经一度流量过大以至于阿里那边发邮件过来要我们关闭这个服务区(这是个免费的服务)。为了继续造福群众,我们做了一些优化流量的措施:

  1. 减少SDK请求的次数
  2. 设计了一种服务器端缓存验证机制

前者是因为很多开发者把调用方法写在了Activity里面,这样每次Activity重建的时候都会导致给服务器发请求。但是对于SDK来说无法判断请求是开发者故意发起的还是由于Activity重建导致的,所以解决这个问题需要开发者配合 - 这明显是不可能的。考虑到在线参数并不会经常性的发生变化,SDK限制了请求间隔为10分钟 - 考虑大部分App的声明周期是3 - 10 分钟(对于读书、视频等媒体类应用例外),这等于App每次启动只能请求一次服务器,这种限制在开发者DEBUG阶段会造成奇怪的问题 - 明明更新了在线参数,本地却不起效果。

第二个措施其实是进一步优化,在最早设计在线参数的时候已经添加了服务器端的验证机制 - 每次请求数据的时候带上服务器返回的最后修改时间,如果服务器端发现数据没有变化,那么就不再返回数据。但是这个协议是在HTTP-Body里面通过私有协议实现的,每次请求服务器的时候依然会发送大量数据(<1K),所以优化的措施是每次先发送一个最简的协议给服务器如果数据有变化再发送一个标准的协议给服务器取回数据。

当时我对HTTP协议并不熟悉,这些设计都是通过私有协议实现的,其实完全可以通过HTTP来实现,这样可以较好的分离控制逻辑和业务数据。



Etag - Last-Modified和Etags如何帮助提高性能?

把Last-Modified和ETags请求的http报头一起使用,这样可利用客户端(例如浏览器)的缓存。因为服务器首先产生Last-Modified/Etag标记,服务器可在稍后使用它来判断页面是否已经被修改。本质上,客户端通过将该记号传回服务器要求服务器验证其(客户端)缓存。
过程如下:
1.客户端请求一个页面(A)。


2.服务器返回页面A,并在给A加上一个Last-Modified/ETag。


3.客户端展现该页面,并将页面连同Last-Modified/ETag一起缓存。


4.客户再次请求页面A,并将上次请求时服务器返回的Last-Modified/ETag一起传递给服务器。


5.服务器检查该Last-Modified或ETag,并判断出该页面自上次客户端请求之后还未被修改,直接返回响应304和一个空的响应体。

 


Etag - 作用

Etag 主要为了解决 Last-Modified 无法解决的一些问题。

1、 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;


2、某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒)

 

3、某些服务器不能精确的得到文件的最后修改时间;

为此,HTTP/1.1 引入了 Etag(Entity Tags).Etag仅仅是一个和文件相关的标记,可以是一个版本标记,比如说v1.0.0或者说"2e681a-6-5d044840"这么一串看起来很神秘的编码。但是HTTP/1.1标准并没有规定Etag的内容是什么或者说要怎么实现,唯一规定的是Etag需要放在""内。

 


Etag - 工作原理

Etag由服务器端生成,客户端通过If-Match或者说If-None-Match这个条件判断请求来验证资源是否修改。常见的是使用If-None-Match.请求一个文件的流程可能如下:

====第一次请求===
1.客户端发起 HTTP GET 请求一个文件;


2.服务器处理请求,返回文件内容和一堆Header,当然包括Etag(例如"2e681a-6-5d044840")(假设服务器支持Etag生成和已经开启了Etag).状态码200

====第二次请求===
1.客户端发起 HTTP GET 请求一个文件,注意这个时候客户端同时发送一个If-None-Match头,这个头的内容就是第一次请求时服务器返回的Etag:2e681a-6-5d044840


2.服务器判断发送过来的Etag和计算出来的Etag匹配,因此If-None-Match为False,不返回200,返回304,客户端继续使用本地缓存;

流程很简单,问题是,如果服务器又设置了Cache-Control:max-age和Expires呢,怎么办?
答案是同时使用,也就是说在完全匹配If-Modified-Since和If-None-Match即检查完修改时间和Etag之后,服务器才能返回304.

 

扩展:HTTP中的缓存机制

网页的缓存是由HTTP消息头中的“Cache-control”来控制的,常见的取值有private、no-cache、max-age、must- revalidate等,默认为private。其作用根据不同的重新浏览方式分为以下几种情况:

(1) 打开新窗口
值为private、no-cache、must-revalidate,那么打开新窗口访问时都会重新访问服务器。
而如果指定了max-age值,那么在此值内的时间里就不会重新访问服务器,例如:
Cache-control: max-age=5(表示当访问此网页后的5秒 内再次访问不会去服务器)

(2) 在地址栏回车
值为private或must-revalidate则只有第一次访问时会访问服务器,以后就不再访问。
值为no-cache,那么每次都会访问。
值为max-age,则在过期之前不会重复访问。

(3) 按后退按扭
值为private、must-revalidate、max-age,则不会重访问,
值为no-cache,则每次都重复访问

(4) 按刷新按扭
  无论为何值,都会重复访问

Cache-control值为“no-cache”时,访问此页面不会在Internet临时文章夹留下页面备份。

 

header常用指令
header分为三部分:
第一部分为HTTP协议的版本(HTTP-Version);
第二部分为状态代码(Status);
第三部分为原因短语(Reason-Phrase)。 

// fix 404 pages: 用这个header指令来解决URL重写产生的404 header 
header('HTTP/1.1 200 OK'); 
  
// set 404 header: 页面没找到
header('HTTP/1.1 404 Not Found'); 
  
//页面被永久删除,可以告诉搜索引擎更新它们的urls
// set Moved Permanently header (good forredrictions) 
// use with location header 
header('HTTP/1.1 301 MovedPermanently');  

// 访问受限
header('HTTP/1.1 403 Forbidden');

// 服务器错误
header('HTTP/1.1 500 Internal Server Error');

 

禁止页面在IE中缓存 

http响应消息头部设置:

CacheControl = no-cache
Pragma=no-cache
Expires = -1 

 

Expires 表示存在时间,允许客户端在这个时间之前不去检查(发请求),等同max-age的 
效果。但是如果同时存在,则被Cache-Control的max-age覆盖。 

 

HTTP响应优化

1.去掉Date, Expires

2.只保留Cache-Control来控制本地缓存


<think>好的,我现在需要回答用户关于OData中@odata.etag的含义和用途的问题。首先,我需要回忆一下OData协议的相关知识,特别是ETag的部分。ETag在HTTP中通常用于缓存验证,但在OData中可能有特定的应用。 根据用户提供的引用,特别是引用[3]提到了服务器端并发控制,这可能与ETag有关。在并发控制中,ETag通常用来检测资源是否被修改,防止覆盖别人的更改。例如,当客户端获取一个资源时,服务器会返回ETag,客户端在更新资源时携带这个ETag,服务器验证ETag是否匹配,如果不匹配则拒绝更新,避免冲突。 接下来,查看用户提供的引用[4],里面有一个示例请求体,里面可能包含ETag的信息。例如,在PATCH请求中,可能需要包含If-Match头,使用ETag值来确保资源未被修改。引用中的示例虽然没有直接显示ETag,但可以推断ETag用于批处理请求中的并发控制。 然后,用户提到的@odata.etag字段,这通常出现在OData的响应体中,比如在JSON数据中作为属性存在。例如,当获取一个实体时,响应里可能会有@odata.etag属性,其值是一个版本标识符。客户端在后续的更新或删除操作中,需要将这个ETag值放在If-Match头中,以启用乐观并发控制。 另外,参考引用[1]中的内容,SAP UI5应用需要保持mock数据与真实OData响应结构一致,包括d和results字段,可能也涉及ETag字段。这说明ETag是OData标准的一部分,不同实现(如SAP ABAP和Microsoft Dynamics 365)都需要支持。 关于ETag的具体用法,需要结合HTTP方法。例如,GET请求返回ETag,PUT或PATCH请求使用If-Match头来指定ETag值。如果资源已被修改,ETag不匹配,服务器返回412 Precondition Failed,这样客户端可以处理冲突。 可能还需要区分实体ETag和属性ETag,但OData中通常是实体级别的ETag。此外,ETag的生成方式由服务器决定,可能是版本号、时间戳或哈希值。 总结一下,用户的问题是关于@odata.etag的作用和用法,需要解释ETag在OData中的用途,特别是在并发控制中的应用,以及如何在请求中使用ETag头来避免数据冲突。同时,结合用户提供的引用资料,特别是关于并发控制和请求示例的部分,来支撑回答的可靠性。</think>### @odata.etag 的含义与用途 **@odata.etag** 是 OData 协议中用于实现**乐观并发控制**的关键字段,其本质是一个实体版本标识符。它的核心作用是帮助客户端和服务端检测数据冲突,确保数据更新的原子性和一致性[^3]。 --- ### 核心功能 1. **并发控制** - 客户端通过 `@odata.etag` 获取资源的当前版本标识符。 - 在更新或删除请求时,客户端需在请求头中携带该值(通过 `If-Match` 或 `If-None-Match`)。 - 服务端会校验 ETag 是否匹配: - **匹配**:允许操作,并更新 ETag。 - **不匹配**:返回 `412 Precondition Failed`,阻止覆盖他人修改[^3][^4]。 2. **数据一致性** - 适用于多用户协作场景(如 CRM、ERP 系统),避免多人同时修改同一数据导致丢失更新。 --- ### 技术实现 #### 1. 响应中的 ETag OData 服务在返回实体数据时,会在 JSON 中附加 `@odata.etag` 字段: ```json { "@odata.etag": "W/\"08D9574D4A3B3F0\"", "id": "123", "name": "Example" } ``` #### 2. 请求中的使用 - **更新操作示例**(携带 ETag): ```http PATCH /api/data/v8.2/accounts(123) HTTP/1.1 If-Match: W/"08D9574D4A3B3F0" Content-Type: application/json {"name": "Updated Name"} ``` 若服务端检测到 ETag 不匹配,返回: ```http HTTP/1.1 412 Precondition Failed ``` #### 3. 强制覆盖(绕过并发控制) 通过 `If-Match: *` 可跳过版本校验: ```http PATCH /api/data/v8.2/accounts(123) HTTP/1.1 If-Match: * Content-Type: application/json {"name": "Force Update"} ``` --- ### 应用场景 - **Dynamics 365 数据同步**:在批量处理(Batch Request)中,每个子请求通过 ETag 确保操作独立性[^4]。 - **SAP UI5 应用开发**:Mock 数据需模拟 `@odata.etag` 以保持与真实服务的行为一致性[^1]。 - **Web API 设计**:符合 OData 4.0 标准的 API 需支持 ETag 实现 RESTful 并发控制[^2]。 --- ### 常见问题 **Q1: ETag 的值如何生成?** 由服务端决定,可以是时间戳、版本号或哈希值。例如 Dynamics 365 使用 `W/"<hex>"` 格式表示弱校验器。 **Q2: 如何禁用并发控制?** 在请求头中设置 `If-Match: *`,但需谨慎使用以避免数据冲突。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值