提问人:Chris Bartow 提问时间:9/5/2008 最后编辑:Stu ThompsonChris Bartow 更新时间:7/6/2011 访问量:7450
如何制作与 Apache 匹配的 etag?
How do you make an etag that matches Apache?
答:
11赞
Chris Bartow
9/5/2008
#1
Apache 使用标准格式 inode-filesize-mtime。唯一需要注意的是,mtime 必须是纪元时间并用零填充,因此它是 16 位数字。以下是在PHP中如何做到这一点:
$fs = stat($file);
header("Etag: ".sprintf('"%x-%x-%s"', $fs['ino'], $fs['size'],base_convert(str_pad($fs['mtime'],16,"0"),10,16)));
评论
1赞
Alix Axel
6/11/2011
为什么不呢?header(sprintf('Etag: "%x-%x-%016x"', $fs['ino'], $fs['size'], $fs['mtime']));
1赞
Halcyon
2/6/2012
我注意到我的 Apache 服务器的 ETag 的 MTime 部分实际上有一个更精确的 MTime,它也使用微秒。因此,如果你想像 Apache 那样生成 ETag,你需要 mtime 的微时间。据我所知,这在PHP中是不可能的。但是,您可以做的是检查 Apache 的 MTime 是否足够接近(<1 秒),因此您至少可以返回一个 .304 Not Modified
1赞
Neall
9/5/2008
#2
但是,如果您动态生成页面,这可能没有意义。如果你使用的是 PHP,你可以选择主脚本的 inode 和文件大小,但修改时间不会告诉你数据是否发生了变化。除非你有一个很好的缓存过程,或者只是生成静态页面,否则 etags 是没有帮助的。如果您确实有良好的缓存过程,则 inode 和文件大小可能无关紧要。
编辑:对于不知道 etag是什么的人来说 - 它们只是一个值,当内容发生变化时会发生变化,用于缓存目的。浏览器从 Web 服务器获取 etag,将其与缓存副本的 etag 进行比较,然后在 etag 发生更改时获取整个页面。
评论
0赞
Matt Kantor
9/17/2012
这种方法对于下载脚本之类的事情很有用,这些脚本只是通过PHP流式传输文件,以及其他响应实际上不是动态的每种请求的情况。
2赞
Hank Gay
9/5/2008
#3
关于Apache的Etag,需要记住的一件事是,它们在集群中不能很好地发挥作用,因为它们包含的inode信息可能(而且可能会)在同一集群中的机器之间有所不同。
评论
3赞
Halcyon
2/11/2012
添加到您的 .htaccess 中,使 Etag inode 独立。FileETag MTime Size
0赞
holmis83
10/26/2016
在 Apache 版本 2.4 中,默认情况下不再包含 INode。
1赞
PWolanin
7/6/2011
#4
上面的答案(来自 Chris)效果很好,但可以使用 sprintf 中的隐式强制转换进行简化:
sprintf('"%x-%x-%x"', $s['ino'], $s['size'], str_pad($s['mtime'], 16, "0"));
建议不起作用,因为填充是在转换为十六进制之后应用的,而不是在转换之前应用的。%016x
评论
0赞
Halcyon
2/6/2012
这不起作用,我不知道为什么,也许是因为 %x 需要作为输入?int
1赞
Matt Kantor
9/17/2012
@FritsvanCampen:事实证明,这比这更复杂一些。 将尝试将字符串强制转换为 ,但由于这些数字太大,它们会溢出并导致问题。解决方案是改用:.sprintf
int
float
sprintf('"%x-%x-%x"', $s['ino'], $s['size'], (float) str_pad($s['mtime'], 16, '0'))
评论