我一直在寻找缓存网站资产的方法,并注意到大多数类似于我的网站使用查询字符串来覆盖缓存(例如:/css/style.css?v=124942823)
之后,我注意到每当我保存我的style.css文件时,最后修改的标题都被“更新”,使查询字符串变得不必要。
所以我想知道:
谢谢!
答案 0 :(得分:63)
为什么这么多网站使用"查询字符串"方法,而不是让最后修改的标题工作吗?
更改查询字符串会更改网址,确保内容为"新鲜"。
我应该取消设置Last-modified标头并使用查询字符串吗?
没有。虽然那个几乎是正确的答案。
网络上使用了三种基本的缓存策略:
为了说明这三种情况,请考虑以下情况:
用户首次访问网站,加载十页并离开。每个页面加载相同的css文件。对于上述每个缓存策略,将会发出多少请求?
在这种情况下,应该清楚的是,没有任何其他因素影响结果,对css文件的10次请求将导致它被发送到客户端(浏览器)10次。
如果使用Last-Modified或Etag,也将成为10个请求。但是其中9个只是标题,并且没有身体被转移。客户端使用条件请求来避免重新下载已有的东西。以此网站的css文件为例。
第一次请求文件时,会发生以下情况:
$ curl -i http://cdn.sstatic.net/stackoverflow/all.css
HTTP/1.1 200 OK
Server: cloudflare-nginx
Date: Mon, 12 May 2014 07:38:31 GMT
Content-Type: text/css
Connection: keep-alive
Set-Cookie: __cfduid=d3fa9eddf76d614f83603a42f3e552f961399880311549; expires=Mon, 23-Dec-2019 23:50:00 GMT; path=/; domain=.sstatic.net; HttpOnly
Cache-Control: public, max-age=604800
Last-Modified: Wed, 30 Apr 2014 22:09:37 GMT
ETag: "8026e7dfc064cf1:0"
Vary: Accept-Encoding
CF-Cache-Status: HIT
Expires: Mon, 19 May 2014 07:38:31 GMT
CF-RAY: 1294f50b2d6b08de-CDG
.avatar-change:hover{backgro.....Some KB of content
对同一网址的后续请求如下所示:
$ curl -i -H "If-Modified-Since:Wed, 30 Apr 2014 22:09:37 GMT" http://cdn.sstatic.net/stackoverflow/all.css
HTTP/1.1 304 Not Modified
Server: cloudflare-nginx
Date: Mon, 12 May 2014 07:40:11 GMT
Content-Type: text/css
Connection: keep-alive
Set-Cookie: __cfduid=d0cc5afd385060dd8ba26265f0ebf40f81399880411024; expires=Mon, 23-Dec-2019 23:50:00 GMT; path=/; domain=.sstatic.net; HttpOnly
Cache-Control: public, max-age=604800
Last-Modified: Wed, 30 Apr 2014 22:09:37 GMT
ETag: "8026e7dfc064cf1:0"
Vary: Accept-Encoding
CF-Cache-Status: HIT
Expires: Mon, 19 May 2014 07:40:11 GMT
CF-RAY: 1294f778e75d04a3-CDG
请注意,没有正文,响应为304 Not Modified。这告诉客户端它已经拥有的内容(在本地缓存中)仍然是新鲜的。
这并不是说这是最佳方案。使用the network tab of chrome developer tools等工具可以让您准确了解请求需要多长时间,以及执行什么操作:
由于响应没有正文,响应时间会少得多,因为要传输的数据较少。但 仍然是一个回应。并且 仍然是连接到远程服务器的所有开销。
如果没有etags,没有最后修改的标头,并且将来只有一个过期标头设置 - 只有第一次访问url才会导致与远程服务器的任何通信。这是well-known? best practice for better frontend performance。如果是这种情况,对于后续请求,客户端将从其自己的缓存中读取内容,而根本不与远程服务器通信。
这具有明显的性能优势,这对于延迟可能很大的移动设备尤其重要(温和地说)。
绕过客户端的缓存,网站使用查询参数。当内容更改时(或者如果发布了新版本的站点),将修改查询参数,因此在URL更改时将请求该文件的 new 版本。这比每次更改时重命名文件更省力/更方便,但它没有问题,
Using query strings prevents proxy caching,在下面的引文中,作者证明来自浏览器< - >代理缓存服务器< - >网站的请求不使用代理缓存:
加载mylogo.gif?v = 1.2两次(清除其间的缓存)结果 在这些标题中:
>> GET http://stevesouders.com/mylogo.gif?v=1.2 HTTP/1.1 << HTTP/1.0 200 OK << Date: Sat, 23 Aug 2008 00:19:34 GMT << Expires: Tue, 21 Aug 2018 00:19:34 GMT << X-Cache: MISS from someserver.com << X-Cache-Lookup: MISS from someserver.com >> GET http://stevesouders.com/mylogo.gif?v=1.2 HTTP/1.1 << HTTP/1.0 200 OK << Date: Sat, 23 Aug 2008 00:19:47 GMT << Expires: Tue, 21 Aug 2018 00:19:47 GMT << X-Cache: MISS from someserver.com << X-Cache-Lookup: MISS from someserver.com
很明显,代理没有提供第二个响应: 缓存响应标题说MISS,Date和Expires值改变, 并且拖尾stevesouders.com访问日志显示两个点击。
这不应该被轻视 - 当访问位于世界另一端的物理位置的网站时,响应时间可能非常慢。从位于路径上的代理服务器获得答案可能意味着网站之间的区别是否可用 - 在永久缓存资源的情况下,这意味着在使用验证请求的情况下,第一次加载网址的速度很慢意味着整个网站都会很迟钝。
&#34; best&#34;解决方案是版本控制文件,以便每当内容发生变化时,网址也会发生变化。通常情况下,这将作为构建过程的一部分自动完成。
然而,近乎妥协的是实施重写规则such as
# ------------------------------------------------------------------------------
# | Filename-based cache busting |
# ------------------------------------------------------------------------------
# If you're not using a build process to manage your filename version revving,
# you might want to consider enabling the following directives to route all
# requests such as `/css/style.12345.css` to `/css/style.css`.
# To understand why this is important and a better idea than `*.css?v231`, read:
# http://stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring
<IfModule mod_rewrite.c>
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpe?g|gif)$ $1.$3 [L]
</IfModule>
通过这种方式,foo.123.css
的请求由服务器处理为foo.css
- 这具有使用查询参数进行缓存清除的所有优点,但没有禁用代理缓存的问题。
答案 1 :(得分:2)
Last-Modified标头在浏览器中的应用方式不同,但通常浏览器会发出条件GET请求,如果需要更新缓存,服务器必须响应该请求。例如,在Firefox中......
&#34; Last-Modified&#34;响应头可以用作弱验证器。 它被认为是弱的,因为它只有1秒的分辨率。如果 &#34;上次修改&#34;头部存在于响应中,然后客户端可以 发出&#34; If-Modified-Since&#34;请求标头以验证缓存 文档。
当发出验证请求时,服务器可以忽略 验证请求和响应正常200 OK,或者它可以返回 304 Not Modified指示浏览器使用其缓存副本。该 后一种响应还可以包括更新过期的标头 缓存文档的时间。
通过设置时间戳(或指纹),您可以明确地让浏览器知道何时需要更新其缓存,然后您可以设置很长的到期时间。
值得注意的是,rails资产管道(http://guides.rubyonrails.org/asset_pipeline.html)上的文档引用了查询字符串时间戳上指纹识别的3个优点:
有关缓存的更多详细信息和最佳做法: https://developers.google.com/speed/docs/best-practices/caching