如何为资源文件生成ETag HTTP标头?
ETag指的是服务器发送给客户端的任意字符串,客户端下次请求该文件时会将该字符串发送回服务器。
ETag应该是基于文件在服务器上计算出来的。有点像校验和,但你可能不想对每个发送出去的文件计算校验和。
server client
<------------- request file foo
file foo etag: "xyz" -------->
<------------- request file foo
etag: "xyz" (what the server just sent)
(the etag is the same, so the server can send a 304)
我建立了一个字符串,格式为“日期时间戳-文件大小-文件inode号”。因此,如果服务器上的文件在向客户端提供服务后发生更改,则新生成的etag在客户端重新请求时将无法匹配。
char *mketag(char *s, struct stat *sb)
{
sprintf(s, "%d-%d-%d", sb->st_mtime, sb->st_size, sb->st_ino);
return s;
}
来自http://developer.yahoo.com/performance/rules.html#etags:
默认情况下,Apache和IIS都会嵌入数据在ETag中,这会大大降低在具有多个服务器的网站上进行有效性测试成功的几率。
...
如果您没有利用ETag提供的灵活验证模型,最好完全删除ETag。
for file in *; do printf "%x-%x-%x\t$file\n" `stat -c%i $file` `stat -c%s $file` $((`stat -c%Y $file`*1000000)) ; done
即使我正在寻找与ETag完全相似的东西(浏览器仅在服务器上的文件发生更改时才请求文件),它从未起作用,最终我使用了一个GET技巧(将时间戳作为GET参数添加到JS文件中)。
shortlink = str(hex(zlib.adler32(link)+(2**32-1)/2))[2:-1]
我建议不要使用它们,而是改用最后修改头。
Askapache有一篇有用的文章介绍了这个。(似乎他们几乎什么都做!)
Mark Harrison的代码示例类似于Apache 2.2中使用的内容。但是当您有两个具有相同文件但文件的inode
不同时,这种算法会导致负载平衡问题。这就是为什么在Apache 2.4中,开发人员简化了ETag模式并删除了inode
部分的原因。此外,为了使ETag更短,通常会以十六进制编码:
<inttypes.h>
char *mketag(char *s, struct stat *sb)
{
sprintf(s, "\"%" PRIx64 "-%" PRIx64 "\"", sb->st_mtime, sb->st_size);
return s;
}
或者对于Java
etag = '"' + Long.toHexString(lastModified) + '-' +
Long.toHexString(contentLength) + '"';
针对C#
// Generate ETag from file's size and last modification time as unix timestamp in seconds from 1970
public static string MakeEtag(long lastMod, long size)
{
string etag = '"' + lastMod.ToString("x") + '-' + size.ToString("x") + '"';
return etag;
}
public static void Main(string[] args)
{
long lastMod = 1578315296;
long size = 1047;
string etag = MakeEtag(lastMod, size);
Console.WriteLine("ETag: " + etag);
//=> ETag: "5e132e20-417"
}
该函数返回与Nginx兼容的ETag。请参阅不同服务器的ETag比较。