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会通过它来控制内置广告的开关,曾经一度流量过大以至于阿里那边发邮件过来要我们关闭这个服务区(这是个免费的服务)。为了继续造福群众,我们做了一些优化流量的措施:
- 减少SDK请求的次数
- 设计了一种服务器端缓存验证机制
前者是因为很多开发者把调用方法写在了Activity里面,这样每次Activity重建的时候都会导致给服务器发请求。但是对于SDK来说无法判断请求是开发者故意发起的还是由于Activity重建导致的,所以解决这个问题需要开发者配合 - 这明显是不可能的。考虑到在线参数并不会经常性的发生变化,SDK限制了请求间隔为10分钟 - 考虑大部分App的声明周期是3 - 10 分钟(对于读书、视频等媒体类应用例外),这等于App每次启动只能请求一次服务器,这种限制在开发者DEBUG阶段会造成奇怪的问题 - 明明更新了在线参数,本地却不起效果。
第二个措施其实是进一步优化,在最早设计在线参数的时候已经添加了服务器端的验证机制 - 每次请求数据的时候带上服务器返回的最后修改时间,如果服务器端发现数据没有变化,那么就不再返回数据。但是这个协议是在HTTP-Body里面通过私有协议实现的,每次请求服务器的时候依然会发送大量数据(<1K),所以优化的措施是每次先发送一个最简的协议给服务器如果数据有变化再发送一个标准的协议给服务器取回数据。
当时我对HTTP协议并不熟悉,这些设计都是通过私有协议实现的,其实完全可以通过HTTP来实现,这样可以较好的分离控制逻辑和业务数据。
作者:ntop
链接:https://www.jianshu.com/p/a3ea9619c38d
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。