我正在尝试缓存我网站 Assets 的方法,并注意到大多数与我类似的网站都使用查询字符串来覆盖缓存(例如:/css/style.css?v=124942823)
之后,我注意到每当我保存我的 style.css 文件时,最后修改的标题都会“更新”,使得查询字符串变得不必要。
所以我想知道:
最佳答案
TL; 博士
Why do so many websites use the "query string" method, instead of just letting the last-modified header do its work?
更改查询字符串会更改 url,确保内容“新鲜”。
Should I unset the Last-modified header and just work with query strings?
不。虽然这几乎是正确的答案。
网络上使用了三种基本的缓存策略:
为了说明所有三个,请考虑以下场景:
用户第一次访问网站,加载十个页面并离开。每个页面加载相同的 css 文件。对于上述每种缓存策略,会发出多少请求?
无缓存:10 个请求
在这种情况下,应该清楚没有其他任何影响结果的因素,对 css 文件的 10 次请求将导致它被发送到客户端(浏览器)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
对同一 url 的后续请求将如下所示:
$ 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 .这告诉客户端它已经拥有(在本地缓存中)该 url 的内容仍然是新鲜的。
这并不是说这是最佳方案。使用 the network tab of chrome developer tools 等工具允许您准确查看请求需要多长时间和做什么:
因为响应没有正文,所以响应时间会少得多,因为要传输的数据更少。但还是有回应。并且仍然存在连接到远程服务器的所有开销。
好处
缺点
永远缓存:1 个请求
如果没有 etags,没有最后修改的 header ,并且只有一个在 future 很远设置的过期 header - 只有第一次访问 url 才会导致与远程服务器的任何通信。这是一个 well-known? best practice for better frontend performance .如果是这种情况,对于后续请求,客户端将从它自己的缓存中读取内容,而根本不与远程服务器通信。
这具有明显的性能优势,这在延迟可能很大的移动设备上尤其显着(委婉地说)。
好处
缺点
不要使用查询字符串进行缓存破坏
站点使用查询参数是为了绕过客户端的缓存。当内容更改时(或者如果发布了新版本的站点),查询参数会被修改,因此当 url 更改时,将请求该文件的新版本。这比每次更改文件时重命名文件更少工作/更方便,但它并非没有问题,
Using query strings prevents proxy caching ,在下面的引用中,作者证明来自浏览器<->代理缓存服务器<->网站的请求不使用代理缓存:
Loading mylogo.gif?v=1.2 twice (clearing the cache in between) results in these headers:
>> 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
Here it’s clear the second response was not served by the proxy: the caching response headers say MISS, the Date and Expires values change, and tailing the stevesouders.com access log shows two hits.
这不应该掉以轻心 - 当访问物理上位于世界另一端的网站时,响应时间可能非常慢。从位于沿途的代理服务器获取答案可能意味着网站可用与否之间的区别 - 在永久缓存资源的情况下,这意味着 url 的第一次加载很慢,在使用验证请求的情况下意味着整个网站将变得缓慢。
取而代之的是版本控制 Assets
“最佳”解决方案是版本控制文件,以便每当内容更改时 url 也会更改。通常,这将作为构建过程的一部分自动化。
然而,几乎要妥协的是实现重写规则 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
- 这具有使用查询参数进行缓存破坏的所有优点,但没有禁用代理缓存的问题。
关于javascript - 文件缓存 : Query string vs Last-Modified?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23603023/