[CDN 技术] HTTP参数中Etag的重要性

这篇文章写的挺好的,所以就转载过来了,谢谢原作者的无私分享

[CDN 技术] HTTP参数中Etag的重要性    http2

Etag在HTTP1.1中有介绍,主要的作用就是在(css file, image, javascript file)文件后面添加一个唯一的参数(相当于查询参数字符串),Etag有服务器端生成,并且随着文件的改变而改变,这样浏览器端就会只重新请求获取 Etag发生变化的文件,减少浏览器端数据的流量,加快浏览器的反应速度,重要的是减轻服务器端的压力,所以服务器端Etag的实现就比较重要了.

现在我们有个问题为什么要使用Etag呢?

Etag主要为了解决Last-Modified无法解决的一些问题.他能比Last_Modified更加精确的知道文件是否被修改过.如果有个 文件修改非常频繁,比如在秒以下的时间内进行修改,比如1秒内修改了10次,If-Modified-Since能检查只能秒级的修改,所以这种修改无法 判断.原因是UNIX记录MTIME只能精确到秒.所以我们选择生成Etag,因为Etag可以综合Inode,MTime和Size,可以避免这个问 题.

Etag的工作原理
Etag在服务器上生成后,客户端通过If-Match或者说If-None-Match这个条件判断请求来验证资源是否修改.我们常见的是使用If-None-Match.请求一个文件的流程可能如下:
新的请求
客户端发起HTTP GET请求一个文件(css ,image,js);服务器处理请求,返回文件内容和一堆Header(包括Etag,例如"2e681a-6-5d044840"),http头状态码为为200.

同一个用户第二次这个文件的请求
客户端在一次发起HTTP GET请求一个文件,注意这个时候客户端同时发送一个If-None-Match头,这个头中会包括上次这个文件的Etag(例如"2e681a- 6-5d044840"),这时服务器判断发送过来的Etag和自己计算出来的Etag,因此If-None-Match为False,不返回200,返 回304,客户端继续使用本地缓存;

注意.服务器又设置了Cache-Control:max-age和Expires时,会同时使用,也就是说在完全匹配If-Modified-Since和If-None-Match即检查完修改时间和Etag之后,服务器才能返回304.

下面是在Apache中的Etag的配置

在Apache中设置Etag的支持比较简单,只需要在apache的配置中加入下面的内容就可以了:

FileETag MTime Size

注解:FileETag指令配置了当文档是基于一个文件时用以创建ETag(实体标签)应答头的文件的属性(ETag的值用于进行缓冲管理以节约网络带 宽).ETag的值由文件的inode(索引节点)、大小、最后修改时间决定.FileETag指令可以让您选择(如果您想进行选择)这其中哪些要素将被 使用.主要关键字如下:

INode
    文件的索引节点(inode)数
MTime
    文件的最后修改日期及时间
Size
    文件的字节数
All
    所有存在的域,等价于:FileETag INode MTime Size
None
    如果一个文档是基于文件的,则不在应答中包含任何ETag头

在大型多WEB集群时,使用ETag时有问题,所以有人建议使用WEB集群时不要使用ETag,其实很好解决,因为多服务器时,INode不一样,所以不 同的服务器生成的ETag不一样,所以用户有可能重复下载(这时ETag就会不准),明白了上面的原理和设置后,解决方法也很容易,让ETag后面二个参 数,MTime和Size就好了.只要ETag的计算没有INode参于计算,就会很准了.


使用 HTTP 缓存

任何一个 WEB 项目,要提高性能,各个环节的缓存必不可少。利用好 HTTP 协议的缓存机制,可以大幅减少传输数据,减少请求,这又是一项收益投入比超高的优化手段。这里把之前我写的 HTTP/1.1 缓存机制介绍翻出来:

首先,服务端可以通过响应头里的 Last-Modified(最后修改时间) 或者 ETag(内容特征) 标记实体。浏览器会存下这些标记,并在下次请求时带上 If-Modified-Since: 上次 Last-Modified 的内容 或 If-None-Match: 上次 ETag 的内容,询问服务端资源是否过期。如果服务端发现并没有过期,直接返回一个状态码为 304、正文为空的响应,告知浏览器使用本地缓存;如果资源有更新,服务端返回状态码 200、新的 Last-Modified、Etag 和正文。这个过程被称之为 HTTP 的协商缓存,通常也叫做弱缓存。

可以看到协商缓存并不会节省连接数,但是在缓存生效时,会大幅减小传输内容(304 响应没有正文,一般只有几百字节)。另外为什么有两个响应头都可以用来实现协商缓存呢?这是因为一开始用的 Last-Modified 有两个问题:1)只能精确到秒,1 秒内的多次变化反映不出来;2)在轮询的负载均衡算法中,如果各机器读到的文件修改时间不一致,有缓存无故失效和缓存不更新的风险。HTTP/1.1 并没有规定 ETag 的生成规则,而一般实现者都是对资源内容做摘要,能解决前面两个问题。

另外一种缓存机制是服务端通过响应头告诉浏览器,在什么时间之前(Expires)或在多长时间之内(Cache-Control: Max-age=xxx),不要再请求服务器了。这个机制我们通常称之为 HTTP 的强缓存。

一旦资源命中强缓存规则后,再次访问完全没有 HTTP 请求(Chrome 开发者工具的 Network 面板依然会显示请求,但是会注明 from cache;Firefox 的 firebug 也类似,会注明 BFCache),这会大幅提升性能。所以我们一般会对 CSS、JS、图片等资源使用强缓存,而入口文件(HTML)一般使用协商缓存或不缓存,这样可以通过修改入口文件中对强缓存资源的引入 URL 来达到即时更新的目的。

这里也解释下为什么有了 Expire,还要有 Cache-Control。也有两个原因:1)Cache-Control 功能更强大,对缓存的控制能力更强;2)Cache-Control 采用的 max-age 是相对时间,不受服务端 / 客户端时间不对的影响。

另外关于浏览器的刷新(F5 / cmd + r)和强刷(Ctrl + F5 / shift + cmd +r):普通刷新会使用协商缓存,忽略强缓存;强刷会忽略浏览器所有缓存(并且请求头会携带 Cache-Control:no-cache 和 Pragma:no-cache,用来通知所有中间节点忽略缓存)。只有从地址栏或收藏夹输入网址、点击链接等情况下,浏览器才会使用强缓存。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章