如何制作与 Apache 匹配的 etag?

Posted

技术标签:

【中文标题】如何制作与 Apache 匹配的 etag?【英文标题】:How do you make an etag that matches Apache? 【发布时间】:2010-09-07 21:06:27 【问题描述】:

我想制作一个与 Apache 生成的内容相匹配的 etag。 apache是​​如何创建它的etags的?

【问题讨论】:

【参考方案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)));

【讨论】:

为什么不header(sprintf('Etag: "%x-%x-%016x"', $fs['ino'], $fs['size'], $fs['mtime'])); 我注意到我的 Apache 服务器的 ETag 的 MTime 部分实际上有一个更精确的 MTime,它也使用微秒。因此,如果您想完全按照 Apache 的方式生成 ETag,您将需要 mtime 的 microtime。据我所知,这在 PHP 中是不可能的。但是,您可以做的是检查 Apache 的 MTime 是否足够接近(304 Not Modified。【参考方案2】:

关于 Apache 的 Etag 需要记住的一点是,它们在集群中不能很好地发挥作用,因为它们包含的 inode 信息可能——而且可能会——在同一集群中的机器之间发生变化。

【讨论】:

FileETag MTime Size 添加到您的 .htaccess 以使 Etag inode 独立。 在 Apache 2.4 版中,默认情况下不再包含 INode。【参考方案3】:

如果您是动态生成页面,那么这可能没有意义。如果您使用 PHP,您可以选择主脚本的 inode 和文件大小,但修改时间不会告诉您数据是否已更改。除非您有良好的缓存过程或只生成静态页面,否则 etag 没有帮助。如果您确实有一个良好的缓存过程,则 inode 和文件大小可能无关紧要。

编辑:对于那些不知道etags 是什么的人来说——它们应该是一个在内容发生变化时发生变化的值,用于缓存目的。浏览器从 Web 服务器获取 etag,将其与 etag 进行比较以获取其缓存副本,然后如果 etag 已更改,则获取整个页面。

【讨论】:

这种方法对于下载脚本(仅通过 PHP 流式传输文件)和其他响应实际上不是每个请求的动态的情况非常有用。【参考方案4】:

上面的答案(来自 Chris)效果很好,但可以使用 sprintf 中的隐式转换来简化:

sprintf('"%x-%x-%x"', $s['ino'], $s['size'], str_pad($s['mtime'], 16, "0"));

建议的%016x 不起作用,因为填充是在转换为十六进制之后应用的,而不是之前。

【讨论】:

工作,我不知道为什么,可能是因为 %x 需要 int 作为输入? @FritsvanCampen:结果比这要复杂一些。 sprintf 将尝试将字符串转换为 int,但由于这些数字太大,它们会溢出并导致问题。解决方案是改用floatsprintf('"%x-%x-%x"', $s['ino'], $s['size'], (float) str_pad($s['mtime'], 16, '0'))

以上是关于如何制作与 Apache 匹配的 etag?的主要内容,如果未能解决你的问题,请参考以下文章

Nginx如何启用ETag,提高访问速度

Apache Pig - 如何获取多个包之间的匹配元素数量?

ETag 与标头过期

Laravel 4:路线与斜杠不匹配,如何制作?

使用哪一个:Expire Header、Last Modified Header 或 ETags

你知道 http 响应头中的 ETag 是如何生成的吗