如何配置ETag与浏览器缓存

10

我已经通过设置.htaccess文件来为静态网站设置了浏览器缓存,具体设置如下:

# BROWER CACHING - 1 Day for images
<filesMatch ".(jpg|jpeg|gif|ico)$">
Header set Cache-Control "max-age=86400, public"
</filesMatch>

我对这些图片有1天的缓存时间很满意,但网站变化频繁,因此我不想缓存CSS和JS文件。
我已经了解了ETag,据我所知,它允许您缓存文件,并设置其创建日期,因此如果客户端下次访问该网站时更新了该文件,它将检查创建日期是否匹配。
1. 我是否正确理解了ETag? 2. 如何配置它?我找了一些信息,但没有找到任何关于它的配置的信息。
4个回答

6

HTTP有几个与缓存相关的特性,它们适用于用户代理(浏览器)缓存和代理缓存(无论是透明的还是非透明的;例如在客户端网络中的代理或紧挨着服务器的反向代理)。这些特性分为两组:过期(可能完全防止请求)和验证(可能防止数据传输)。

实体标签 (ETag) 是其中之一,属于验证组的一部分。该组中的另一个是上次修改时间 (Last-Modified)。实体标签允许因内容更改而进行缓存失效,而不是仅因为上次修改时间更新。 在维基百科上 了解实体标签的工作原理。简而言之,典型的用法是:

  1. 服务器在响应包含正在服务的资源的响应中添加 ETag 标头。

  2. 客户端缓存该资源并记住其实体标签(即 ETag 的值)。

  3. 下一次客户端需要该资源时,它会以条件方式从服务器请求。在请求中,它包括包含实体标签的 If-None-Match 标头。

  4. 如果资源已更改(服务器认为 If-None-Match 中的实体标签已过期),则服务器发送包含当前版本资源的响应(和新的实体标签),否则它只响应 304 Not Modified 并不再次发送资源。

对于静态文件(不是由CGI脚本或其他方式动态创建的,每个请求都相同的文件),Apache可以通过FileETag指令来生成ETag默认情况下,如果您没有更改配置,则Apache将生成ETag,其值将基于文件的最后修改时间(mtime)和大小在Apache 2.4中。 在Apache 2.3.14中,默认情况还包括文件的inode号。

如果文件是动态提供的,则Apache无法生成ETag,因为它不知道要缓存的资源生成的详细信息。需要脚本适当设置ETag并处理If-None-Match。例如,在mod_perl中,If-None-Match部分可以使用Apache2::Request::meets_conditions来处理,该模块实现了HTTP / 1.1条件请求的处理。
如果想仅依赖ETag,则需禁用其他验证功能和过期机制。设置Cache-Control:max-age = 0,must-revalidate和Expires:0以强制重新验证缓存条目(即始终进行请求)。还可以从响应中删除Last-Modified标头,但一般情况下HTTP / 1.1不建议这样做。

如果要比较Last-ModifiedETag,请参考以下内容:

请注意,Last-Modified 被视为 HTTP/1.0 兼容性特性ETag 可以包含相同的值并且完全相同(除了使用 If-None-Match 代替 If-Modified-Since)。

作为一则附注,我想补充说明提出的标准RFC 7232已经存在,并且与实体标签和条件请求的详细信息有关。请参见其附录A,了解它引入的从HTTP/1.1所做的更改

6
你可以使用FileETag MTime SizeHeader unset EtagFileEtag none。不要同时使用两种方法(创建ETag和删除ETag),只需选择在您的特定服务器上最有效的方法即可。
# Create the ETag (entity tag) response header field
FileETag MTime Size

或者

# Remove the ETag (entity tag) response header field
Header unset ETag
FileETag none

3
ETAG不是最重要的属性。你缺少的主要属性是过期时间(expires)。我可以百分之百肯定,浏览器缓存可以在没有ETAG的情况下工作。请检查http://pisrs.si上的以下配置。如何检查?按F12,进入网络选项卡,查看资源获取方式,并与你的网站进行比较。本地主机资源有不同的缓存方式。请检查你的浏览器信息。
以下是主域名的可用配置,确保你已启用必要的模块。
<IfModule mod_mime.c>
    AddType text/css .css
    AddType application/x-javascript .js
    AddType image/bmp .bmp
    AddType image/gif .gif
    AddType application/x-gzip .gz .gzip
    AddType image/x-icon .ico
    AddType image/jpeg .jpg .jpeg .jpe
    AddType image/png .png
    AddType application/x-font-ttf .ttf .ttc
    AddType application/zip .zip
</IfModule>
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType text/css A31536000
    ExpiresByType application/x-javascript A31536000
    ExpiresByType application/javascript A31536000
    ExpiresByType text/javascript A31536000
    ExpiresByType text/x-js A31536000
    ExpiresByType image/bmp A31536000
    ExpiresByType image/gif A31536000
    ExpiresByType application/x-gzip A31536000
    ExpiresByType image/x-icon A31536000
    ExpiresByType image/jpeg A31536000
    ExpiresByType application/x-font-otf A31536000
    ExpiresByType image/png A31536000
    ExpiresByType application/x-font-ttf A31536000
    ExpiresByType application/zip A31536000
</IfModule>
<IfModule mod_deflate.c>
    <IfModule mod_headers.c>
        Header append Vary User-Agent env=!dont-vary
    </IfModule>
        AddOutputFilterByType DEFLATE text/html text/css text/x-component application/x-javascript application/javascript text/javascript text/x-js text/plain image/x-icon image/png image/gif
    <IfModule mod_mime.c>
        # DEFLATE by extension
        AddOutputFilter DEFLATE js css htm html xml png gif
    </IfModule>
</IfModule>
<FilesMatch "\.(gif|ico|jpg|jpeg|png|GIF|ICO|JPG|JPEG|PNG|css|js|woff|CSS|JS|WOFF|ttf|TTF)$">
    <IfModule mod_headers.c>
         Header unset Set-Cookie
         Header set Cache-Control "max-age=31536000, public"
    </IfModule>
</FilesMatch>

2
ETags是唯一的不透明标记,除了相等性外,您无法进行比较。因此,如果对于同一资源(例如URI)有2个ETag,则无法确定哪个资源更新。为此,您需要使用Last-Modified头信息。
即使是Last-Modified头信息也存在问题,因为它只能解析到1秒的分辨率,在经常修改的网站(如热门博客)上,缓存很可能具有具有不同ETags和相同Last-Modified值的文件的多个表示。遗憾的是,他们没有考虑使ETags单调递增,以便可以进行比较。
ETag在带有If-None-Match头信息的条件请求中用于GET,并在PUT的情况下使用If-Match,第一种情况下,仅当提供的所有ETag与资源的当前ETag不匹配时(它已更改),服务器才应返回完整正文;而在第二种情况下(对于PUT或PATCH),仅当它匹配时才返回,以便您使用正确的版本。
ETag和Last-Modified都是缓存验证器头信息。大多数缓存的好处涉及“新鲜度”的概念。验证器允许您检查您拥有的版本是否仍然有效,但这仍然需要向服务器发出请求。您可以节省的是有效载荷传输,但对于现今的许多事情来说,这并不值得。
另一方面,“新鲜度”(Expires头信息或max-age Cache-Control指令)允许客户端避免重新验证,如果他们已经拥有的版本仍然是新鲜的(未过期)。这样可以节省连接到服务器进行检查的时间,并且可以在页面加载中节省大量时间。

我不同意。在我们的代理缓存中,能够根据Etag的比较来排除一些表示形式会非常有用。 - Adrien

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接