启用Apache中CSS和JS文件的缓存

14

使用Debian 8.2上的Apache 2.4,我正在尝试启用所有CSS和JS文件的缓存。 图片的缓存正常工作;也就是说,浏览器接收到304状态码,因此不会再次下载。但我无法使其他文件的缓存工作。

我在虚拟主机文件中使用以下代码:

<IfModule mod_expires.c>
    <FilesMatch "\.(jpe?g|png|gif|js|css)$">
        ExpiresActive On
        ExpiresDefault "access plus 1 week"
    </FilesMatch>
</IfModule>
expires 模块已启用。我已重新启动了 apache,并清除了浏览器的 cookies,但没有成功。
从浏览器开发工具中查看 gif 图像的响应:
Cache-Control:max-age=604800
Connection:Keep-Alive
Date:Wed, 25 Nov 2015 21:37:50 GMT
ETag:"4174a-4e69c97fbf080"
Expires:Wed, 02 Dec 2015 21:37:50 GMT
Keep-Alive:timeout=5, max=100
Server:Apache/2.4.10 (Debian)

CSS文件的响应:

Accept-Ranges:bytes
Cache-Control:max-age=604800
Connection:Keep-Alive
Content-Encoding:gzip
Content-Length:135
Content-Type:text/css
Date:Wed, 25 Nov 2015 21:37:50 GMT
ETag:"5116-525639d271c78-gzip"
Expires:Wed, 02 Dec 2015 21:37:50 GMT
Keep-Alive:timeout=5, max=99
Last-Modified:Wed, 25 Nov 2015 20:50:52 GMT
Server:Apache/2.4.10 (Debian)
Vary:Accept-Encoding

看起来expires标题设置正确,但浏览器仍然会请求文件(200 OK)。

我已经尝试了Chrome和Firefox。

概述:

1.)当我在网站内部跟随链接时,浏览器使用缓存文件。但是当我按F5键时,它们重新下载css和js文件,但不重新下载图像。图像返回304。这很好。

2.)当我按Ctrl-F5键时,自然而然地,所有文件都会重新下载。这也很好。

3.)因此问题在于如何启用其他文件的缓存(就像图像一样)。为什么Apache会区分图像和其他文件?我在配置文件中没有给图片放置任何特殊内容。

问题:如何正确启用css和js文件的缓存?

另一个问题:是否有一种特殊的HTTP标头表示浏览器永远不会请求该文件。原因是,即使发送请求以检查文件是否已修改需要100-200毫秒,这也太多了。我确信文件不会被修改。如果它们被修改,我可以轻松地在css文件末尾放置版本字符串,例如myFile.css?v=1.1。所以我希望有一种方法完全停止发送请求。

已解决

首先,在下面的答案中提到了Apache中存在错误。

其次,我有一个误解。我猜这就是现代浏览器的工作方式:

1.)在网站内部跟随链接:不会发送请求,甚至不会检查文件是否已修改。

2.)按F5:发送请求。如果文件未被修改,则服务器将返回304。

3.)Ctrl+F5:完全下载。

关于F5的行为对我来说没有意义。无论如何。

如果有人需要,这里是我在虚拟主机文件中放置的可行解决方案:

RequestHeader  edit "If-None-Match" "^\"(.*)-gzip\"$" "\"$1\""
Header  edit "ETag" "^\"(.*[^g][^z][^i][^p])\"$" "\"$1-gzip\""

LoadModule expires_module /usr/lib/apache2/modules/mod_expires.so
ExpiresActive On

<FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$">
    ExpiresDefault "access plus 4 weeks"
</FilesMatch>
2个回答

3
关闭ETags,在启用gzip的情况下,它们在Apache中表现不佳,会影响304。

请参见此处:Apache is not sending 304 response (if mod_deflate and AddOutputFilterByType is enabled)

由于图像已经压缩,因此通常不使用gzip,这就是它们起作用的原因。

在我看来,ETags在其当前的实现中并没有那么有用(有关更深入的讨论,请参阅我的博客here),因此与上述错误结合在一起,我将它们关闭。

对于第二个问题,只需设置长时间到期时间。

如下所述,有三种情况:

  1. 正常浏览-应该使用缓存,并仅在过期后缓存仍然有效时使用304(在这种情况下,它被设置为相同的到期时间)。

  2. F5或刷新按钮。这是用户明确确认页面及其所有资源仍然有效的操作,因此将对它们进行双重检查(即使那些仍在缓存中且根据到期标头仍然有效),当它们没有更改时,将发送304。它并不意味着“只重新下载已过期的任何内容,但让缓存的项目不变,因为它们仍然是有效的”,就像您认为应该的那样。个人认为浏览器使用的当前实现是有道理的,并且您的方法可能会让最终用户感到困惑。虽然某些网站可能会对图像、CSS和JavaScript等资源进行版本控制,因此重新检查是浪费时间的,但并非所有此类网站都这样做。

  3. Ctrl+F5. 这是强制刷新。它的意思是“忽略缓存并下载全部内容”。除了开发人员在开发服务器上请求更改文件之外,它很少被使用。

希望这一切都说得清楚明白。

编辑于2016年5月12日:看起来Firefox正在引入您实际需要的功能:https://bitsup.blogspot.ie/2016/05/cache-control-immutable.html?m=1


为什么只是部分地呢?我不知道浏览器使用 HEAD 请求。这样做没有太多意义,因为必须跟进一个完整的请求,所以它们只使用条件 GET 请求并一次性完成所有操作。 - Barry Pollard
F5进行手动刷新以检查更新,忽略缓存并发送条件GET请求,如果文件未被修改,则会收到304响应(忽略Apache的错误)。CTRL+F5表示进行完整的GET请求,即使您的缓存中已经有一个文件且仍然有效,因此您永远不应该收到304响应。当您认为缓存错误时(例如,您将文件恢复为服务器上的先前版本,因此尽管最后修改时间不在之后,您仍希望下载它),CTRL+F5非常有用。 - Barry Pollard
为什么要刷新页面,如果你知道它不会有任何变化呢? :-) 我猜你在考虑的情况是页面 HTML 可能会有所不同(假设没有缓存),但图片不会改变(已经缓存),所以你更喜欢只下载页面 HTML?然而这并不是这样工作的 - F5 的意思是“检查所有内容,看看是否需要刷新”。我想浏览器可以实现一个轻量级版本(例如 Alt-F5),表示“仅刷新过期资源”,就像当你再次浏览该页面时一样 - 但可能比值得拥有3种刷新类型更加混乱。 - Barry Pollard
最近看到了这篇帖子,让我想起了你在这里想要的内容:https://bitsup.blogspot.ie/2016/05/cache-control-immutable.html?m=1 - Barry Pollard
那里有很多双重否定,让我感到困惑!;-) - Barry Pollard
显示剩余2条评论

1
如果其他方法都不起作用,请不要忘记在浏览器的开发工具中打开禁用缓存!!!

enter image description here


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