【问题标题】:HTTP: Generating ETag HeaderHTTP:生成 ETag 标头
【发布时间】:2010-09-05 11:52:06
【问题描述】:

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

【问题讨论】:

    标签: language-agnostic http webserver header etag


    【解决方案1】:

    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;
    }
    

    【讨论】:

    • 如果mtime是文件最后修改的时间,那么size和inode的作用是什么?
    • 就我而言,这是因为它是来自 CGI 程序的计算路径。你是对的,在直接路径的情况下,mtime 可能就足够了。由于成本主要在 stat() 中,因此包含 inode 和大小不会产生额外费用,这可能会防止(当然,非常不可能)流氓管理员可能会更新文件并将其返回到原来的mtime。
    • @MarkHarrison,为什么需要在 etag 周围加上双引号?它是语法的强制性部分吗?
    【解决方案2】:

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

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

    ...

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

    【讨论】:

      【解决方案3】:

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

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

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

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

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

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

      【讨论】:

        【解决方案4】:

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

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

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

        【讨论】:

        • 嗯,真可惜,希望他们能尽快恢复,因为该网站是建议的金矿!
        • @RichBradshaw 只是一个问题,我们如何知道资源的最后修改时间戳?浏览数据库更改历史记录后是否完全是手动操作?或者有没有自动化的方法?
        【解决方案5】:

        如何在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 技巧(添加时间戳作为 get 参数js 文件)。

        【讨论】:

          【解决方案6】:

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

           shortlink = str(hex(zlib.adler32(link)+(2**32-1)/2))[2:-1]
          

          【讨论】:

            【解决方案7】:

            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。见comparison of ETags form different servers

            【讨论】:

              猜你喜欢
              • 2011-12-06
              • 2010-10-23
              • 2010-09-21
              • 2016-08-03
              • 2016-06-07
              • 2010-10-04
              • 1970-01-01
              • 2017-03-22
              • 2016-10-28
              相关资源
              最近更新 更多