Nginx Etag学习

  • Nginx Etag
  • 什么是Etag
  • Last-Modified / If-Modified-Since
  • Etag工作原理
  • 为什么要使用Etag
  • Etag字符含义
  • 强Etag和弱Etag
  • Etag丢失问题
  • Etag配置
  • Etag带来的问题


Nginx Etag

什么是Etag

Etag其实是一个页面的Hash值,当浏览器刷新页面的时候,浏览器会发送页面的Etag值,让服务器进行比较,服务器如果发现eTag值没变,则返回304,浏览器则从缓存中获取页面,如果不相等,则重新获取页面,
如果eTag过期,则重新获取页面。

Last-Modified / If-Modified-Since

当请求一个页面时,如果浏览器使用本地缓存,因此我们经常会看到一个HTTP请求为304状态。或者显示200状态,在chrome下标注是from cache,在火狐下会标注BFCache;

我们希望在服务器端更新了静态文件(如css、js、图片),能够在客户端得到及时的更新,但又不想让浏览器每次请求都从服务器端获取静态资源。那么就需要用到Last-Modified/if-Modified-Since

当浏览器第一次请求一个url时,服务器端的返回状态码为200,同时HTTP响应头会有一个Last-Modified标记着文件在服务器端最后被修改的时间

nginx Etag 不起作用 nginx etag配置_etag


览器第二次请求上次请求过的url时,浏览器会在HTTP请求头添加一个If-Modified-Since的标记,用来询问服务器该时间之后文件是否被修改过.

nginx Etag 不起作用 nginx etag配置_服务器_02


如果服务器端的资源没有变化,则自动返回304状态,使用浏览器缓存,从而保证了浏览器不会重复从服务器端获取资源,也保证了服务器有变化是,客户端能够及时得到最新的资源。

Etag工作原理

当浏览器第一次请求一个url时,服务器端的返回状态码为200,同时HTTP响应头会有一个Etag,存放着服务器端生成的一个序列值

nginx Etag 不起作用 nginx etag配置_服务器端_03


浏览器第二次请求上次请求过的url时,浏览器会在HTTP请求头添加一个If-None-Match的标记,用来询问服务器该文件有没有被修改。

nginx Etag 不起作用 nginx etag配置_服务器端_04

为什么要使用Etag

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

  1. 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;
  2. 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒)
  3. 某些服务器不能精确的得到文件的最后修改时间;

为此,HTTP/1.1引入了Etag(EntityTags)

Etag字符含义

Etag"2e681a-6-5d044840"
这里面的三个段,分别代表了INode,MTime,Size根据算法算出的值的Hex格式(不要误以为Etag就是固定的3段式)

强Etag和弱Etag

强Etag根据配置文件中的配置来设置Etag值,默认的Apache的FileEtag设置为:
FileEtag INode Mtime Size
也就是根据这三个属性来生成Etag值,他们之间通过一些算法来实现,并输出成hex的格式,相邻属性之间用-分隔,比如:Etag “2e681a-6-5d044840”

弱Etag是在前面加个W/
如下形式

强ETag表示形式:"22FAA065-2664-4197-9C5E-C92EA03D0A16"。

弱ETag表现形式:w/"22FAA065-2664-4197-9C5E-C92EA03D0A16"。

强、弱ETag类型的出现与Apache服务器计算ETag的方式有关。Apache默认通过FileEtag中FileEtag INode Mtime Size的配置自动生成ETag(当然也可以通过用户自定义的方式)。

假设服务端的资源频繁被修改(如1秒内修改了N次),此时如果有用户将Apache的配置改为MTime,由于MTime只能精确到秒,那么就可以避免强ETag在1秒内的ETag总是不同而频繁刷新Cache(如果资源在秒级经常被修改,也可以通过Last-Modified来解决)。

如果是这种情况,Apache会自动判断请求时间和修改时间之间的差值,如果小于1s,Apache会认为这个文件在这1秒内可能会再次被修改,因此生成一个弱Etag(WeakEtag),这个Etag仅仅基于MTime来生成,因此MTime只能精确到s,所以1s内生成的Etag总是一样,这样就避免了使用强Etag造成的1s内频繁的刷新Cache的情况。(貌似不用Etag,仅仅使用Last-Modified就可以解决,但是这针对的仅仅是修改超级频繁的情况,很多文件可能同时也使用强Etag验证)。

Etag丢失问题

nginx 在开启了 gzip 之后,如果有 ETAG 则会调用 ngx_http_clear_etag 将其清除。从 nginx 1.7.3 这个版本之后,nginx 不再强硬地清除 ETAG 了,而是换了一种 weak ETAG 的策略。

Etag配置

nginx是默认开始etag的。
关闭

etag off;

Etag带来的问题

ETag的问题在于通常使用某些属性来构造它,有些属性对于特定的部署了网站的服务器来说是唯一的。当使用集群服务器的时候,浏览器从一台服务器上获取了原始组件,之后又向另外一台不同的服务器发起条件GET请求,ETag就会出现不匹配的状况。

解决思路:

  1. 如果使用Last-Modified不会出现任何问题,可以直接移除ETag,google的搜索首页则没有使用ETag。
  2. 确定要使用ETag,在配置ETag的值的时候,移除可能影响到组件集群服务器验证的属性,例如只包含组件大小和时间戳。