文档中心 >Google PageSpeed

配置ETag

概览

通过利用ETag的发回一个304未修改响应减少载荷大小。就是说,从Web服务器取数据的时候,如果文件变化了,就取新的文件,如果文件没有变化,只需告诉客户端没有变化即可,不必再把文件取回来,这样就可节省大量的网络带宽和资源。

Etag工作原理

HTTP 协议规格说明定义ETag为"被请求变量的实体标记" (参见14.19)。简单点即服务器响应时给请求URL标记,并在HTTP响应头中将其传送到客户端,类似服务器端返回的格式:

Etag: "5d8c72a5edda8d6a:3239″

客户端的查询更新格式是这样的:

If-None-Match: "5d8c72a5edda8d6a:3239″

如果ETag没改变,则返回状态304。即在客户端发出请求后,Http Reponse Header中包含 Etag: "5d8c72a5edda8d6a:3239″标识,等于告诉Client端,你拿到的这个的资源有表示ID:5d8c72a5edda8d6a:3239。当下次需要发Request索要同一个URI的时候,浏览器同时发出一个If-None-Match报头( Http RequestHeader),此时包头中信息包含上次访问得到的Etag: "5d8c72a5edda8d6a:3239″标识。If-None-Match: "5d8c72a5edda8d6a:3239",这样,Client端等于Cache了两份,服务器端就会比对2者的etag。如果If-None-Match为False,不返回200,返回304 (Not Modified) Response。

ETag的弊端

实体标记(ETags)是一种机制,Web服务器和浏览器使用,以确定缓存在浏览器的组件是否匹配服务器上的来源。 (一个“实体”是图像、脚本、样式表等)

由于通常ETag的使用属性,是由使他们唯一的托管网站的特定服务器构造,所以当浏览器从一台服务器获取原始组件,并随后试图验证该组件在不同的服务器上时,是不匹配的。

ETag的问题是,它们通常使用的属性,是由使他们唯一的托管站点的特定服务器构成。当浏览器获取原始组件从一台服务器,并随后试图验证该组件在不同的服务器上,是不匹配的,因为使用服务器集群来处理请求的Web站点是很常见的。默认情况下,Apache和IIS中的ETag,对于使用多个服务器的网站来说,大大降低了有效性测试成功率。

建议

在Apache 1.3和2.x,ETag格式是 inode-size-timestamp。虽然给定的文件可以驻留在多个服务器上相同的目录,并有相同的文件大小,权限,时间戳记等,但其索引节点inode在各个服务器是不同的。

IIS 5.0和6.0的ETags有一个类似的问题,在IIS,ETags的格式是 Filetimestamp: ChangeNumberChangeNumber是一个用来跟踪IIS配置更改的计数器。一个网站的所有IIS服务器的ChangeNumber是不太可能相同的。

最终的结果是由Apache和IIS为完全相同的组件生成的ETag的在各个服务器之间的不匹配。如果ETag的不匹配,则用户不会收到为ETag设计的小而速度快的304响应;相反,他们会得到一个正常的200响应以及对组件的所有数据。如果您的网站只是在一个服务器上,这不是一个问题。但如果你有多台服务器托管你的网站,而你正在使用Apache或IIS使用默认的ETag配置,那么用户打开网页就会变慢,服务器负载变高,你消耗的带宽变大,以及代理不能高效缓存内容。即使你的组件有一个Expires头,每当用户点击刷新或刷新一个条件GET请求仍进行。

Apache删除ETag

如果你没有从ETag提供的灵活的验证模式获得好处,那么最好把ETag删除。 Last-Modified头验证是基于组件的时间戳。去除ETag可以减少HTTP头在响应和后续请求时的大小。在Apache中,通过简单地添加以下行到你的Apache配置文件.htaccess可以去除ETag:

 FileETag none

IIS删除ETag

  • 方法(1):在IIS服务器站点属性中的“HTTP头”中添加一个自定义Etag头,头名:Etag,值为空。
  • 方法(2):下载remEtag,在网站的ISAPI中加入DLL筛选。

Lighttpd删除ETag

在Lighttpd中设置禁用Etag:

etag.use-inode: "disable" #是否使用inode作为Etag,默认是"enable",设为"disable"是不启用Etag功能
etag.use-mtime: "disable" #是否使用文件修改时间作为Etag
etag.use-size: "disable" #是否使用文件大小作为Etag
static-file.etags: "disable" #是否启用Etag的功能,enable or disable

Nginx删除ETag

1.3.3版本以下的Nginx是没有ETag功能的,要在Nginx中支持ETag功能,可参考Nginx添加ETag的方法

Nginx从1.3.3版开始原生支持ETag,目前尚处于开发阶段,稳定性有风险。

验证的小结如下:

  • 支持的功能
    a)可以通过配置使能或者禁止etag功能。
    配置指令为:"etag on | off;"缺省为on
    b)使能etag后,http响应会包含有etag头,即ETAG:"xxxxxx"。(注意,引号也是etag的一部分)
    c)客户端的http请求中如果包含“If-None-Match”头(nginx对此header不区分大小写),module就会比较该值和计算出的etag,一致就返回304。
    d)If-Modified-Since和If-None-Match是与的关系,即均满足条件才返回304。
    e)支持“If-Match”头。
  • 功能限制
    a)不支持weak tag,即模糊匹配。
    b)不能由应用自定义etag的构成,etag的生成算法固定为:
    last_modified_time+"-"+content_length。即etag与文件的最后修改时间和文件大小有关。
  • etag功能的实现
    不像"nginx-dynamic-etags"简单的采用filter机制,nginx将etag的功能分散在http的处理逻辑的相关代码中体现。

几种Web服务器ETag配置方法

1、Apache设置Etag

在Apache中设置Etag的支持比较简单,只用在含有静态文件的目录中建立一个文件.htaccess, 里面加入:

FileETag MTime Size

这样就行了,详细的可以参考Apache的FileEtag文档页

2、Lighttpd设置Etag

在Lighttpd中设置Etag支持:

etag.use-inode: "enable" #是否使用inode作为Etag,默认是"enable",设为"disable"是不启用Etag功能
etag.use-mtime: "enable" #是否使用文件修改时间作为Etag
etag.use-size: "enable" #是否使用文件大小作为Etag
static-file.etags: "enable" #是否启用Etag的功能,enable or disable

第四个参数肯定是要enable的, 前面三个就看实际的需要来选吧,推荐使用修改时间

3、Nginx添加Etag

1.3.3版本以下的Nginx中默认没有添加对Etag标识,1.3.4版本以上的Nginx增加了ETag功能。如果你使用的是1.3.4以上的版本,那么可以很简单的通过如下设置,启用或关闭ETag功能:

配置指令为:"etag on | off;"缺省为on

如果你使用的是1.3.3以下的版本,则可以用第三方nginx-static-etags模块,添加ETag标识。下面说说该模块的安装。

首先下载Etag源文件,Etag源地址:https://github.com/mikewest/nginx-static-etags。下载后,需要使用Git编译,如果你的服务器没有安装Git,请参考这篇文章CentOS下两种方法安装Git,编译Etag后生成的文件名为 mikewest-nginx-static-etags-25bfaf9.tar.gz   。

安装步骤:

1、Etag文件 mikewest-nginx-static-etags-25bfaf9.tar.gz    路径/root/soft/mikewest-nginx-static-etags-25bfaf9.tar.gz

2、重新编译nginx,添加Etag模块

   a.     nginx -V     //获取nginx的编译参数 --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module 
   b.     cd /root/soft 
          tar zxvf   mikewest-nginx-static-etags-25bfaf9.tar.gz   
          echo '' >> /root/soft/ mikewest-nginx-static-etags-25bfaf9/ngx_http_static_etags_module.c   //bug  增添一空行,否则编译不过
          cd /root/soft/nginx1.0.0
          ./configure  --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module  --add-module=/root/soft/mikewest-nginx-static-etags-25bfaf9         //注意后面添加的路径要对
          make     //这里确记不要make install,否则有可能把当前的配置文件覆盖,影响当前业务。
          cp  /usr/local/nginx/sbin/nginx  /usr/local/nginx/sbin/nginx.bak    //备份个比较安全,出错马上还原回去
          cp objs/nginx  /usr/local/nginx/sbin/nginx.tmp      //替换成新的nginx
          rm -rf  /usr/local/nginx/sbin/nginx  && mv  /usr/local/nginx/sbin/nginx.tmp   /usr/local/nginx/sbin/nginx
          /usr/local/nginx/sbin/nginx  -t        
          kill -USR2 `cat /usr/local/nginx/logs/nginx.pid`   //让nginx把nginx.pid改成nginx.pid.oldbin 并启动新的nginx
          kill -QUIT `cat /usr/local/nginx/logs/nginx.pid.oldbin`  //习惯使用nginx -s reload来重启,发现不能生效,以为我配置错了花一个早上时间找问题。
  c.    修改nginx.conf
          location ~ .*/.(gif|jpg|jpeg|png|bmp|ico|rar|css|js|zip|xml|txt|flv|swf|mid|doc|cur|xls|pdf|txt|)$
           {
          FileETag on;
          etag_format "%X%X";
expires 30d;
           }

           /usr/local/nginx/sbin/nginx  -t 
           /usr/local/nginx/sbin/nginx  -s reload

然后用curl测试看看

           curl --head http://www.***.com/css/style.css