27

如何为资源文件生成 ETag HTTP 标头?

4

7 回答 7

19

只要它在资源表示发生变化时发生变化,您如何生成它完全取决于您。

您应该尝试以另外一种方式生产它:

  1. 不需要您在每个条件 GET 上重新计算它,并且
  2. 如果资源内容未更改,则不会更改

如果您不将计算的哈希值与文件一起存储,则使用内容的哈希值可能会导致您在#1 失败。

如果您重新排列文件系统或从多个服务器提供内容,使用 inode 编号可能会导致您在 #2 失败。

一种可行的机制是使用完全依赖于内容的东西,例如 SHA-1 哈希或版本字符串,只要资源内容发生更改,就会计算和存储一次。

于 2008-08-09T13:50:17.863 回答
17

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)

我建立了一个格式为“dateamp-file size-file inode number”的字符串。因此,如果在将文件提供给客户端后在服务器上更改了文件,则如果客户端重新请求,新生成的 etag 将不匹配。

char *mketag(char *s, struct stat *sb)
{
    sprintf(s, "%d-%d-%d", sb->st_mtime, sb->st_size, sb->st_ino);
    return s;
}
于 2008-08-07T08:57:37.993 回答
6

来自http://developer.yahoo.com/performance/rules.html#etags

默认情况下,Apache 和 IIS 都在 ETag 中嵌入数据,这大大降低了有效性测试在具有多个服务器的网站上成功的几率。

...

如果您没有利用 ETag 提供的灵活验证模型,最好完全删除 ETag。

于 2008-08-07T10:13:20.477 回答
2

如何在 bash 中生成默认的 apache 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 技巧(添加时间戳作为 js 文件的 get 参数)。

于 2011-09-05T12:38:09.460 回答
1

我一直在使用 Adler-32 作为 html 链接缩短器。我不确定这是否是一个好主意,但到目前为止,我还没有注意到任何重复。它可以用作 etag 生成器。并且它应该比尝试使用像 sha 这样的加密方案进行散列更快,但我还没有验证这一点。我使用的代码是:

 shortlink = str(hex(zlib.adler32(link)+(2**32-1)/2))[2:-1]
于 2012-12-27T15:58:39.510 回答
0

我建议不要使用它们,而是使用最后修改的标题。

Askapache 对此有一篇有用的文章。(因为他们几乎做了所有看起来的事情!)

http://www.askapache.com/htaccess/apache-speed-etags.html

于 2008-09-19T22:31:32.220 回答
0

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 的比较

于 2020-07-26T19:17:37.877 回答