配置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: ChangeNumber。ChangeNumber是一个用来跟踪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