文件缓存:查询字符串vs Last-Modified?

Tom*_*Tom 35 html javascript css apache caching

我一直在寻找缓存网站资产的方法,并注意到大多数类似于我的网站使用查询字符串来覆盖缓存(例如:/css/style.css?v=124942823)

之后,我注意到每当我保存我的style.css文件时,最后修改的标题都被"更新",使查询字符串变得不必要.

所以我想知道:

  • 为什么这么多网站使用"查询字符串"方法,而不是让最后修改的标题工作?
  • 我应该取消设置Last-modified标头并使用查询字符串吗?(这有什么特别的优势吗?)

谢谢!

AD7*_*six 66

TL; DR

为什么这么多网站使用"查询字符串"方法,而不是让最后修改的标题工作?

更改查询字符串会更改网址,确保内容"新鲜".

我应该取消设置Last-modified标头并使用查询字符串吗?

不,虽然这几乎是正确的答案.


网络上使用了三种基本的缓存策略:

  • 没有缓存或缓存禁用
  • 使用验证/条件请求
  • 永远缓存

为了说明这三种情况,请考虑以下情形:

用户第一次访问网站,加载十页并离开.每个页面加载相同的css文件.对于上述每个缓存策略,将提出多少请求?

没有缓存:10个请求

在这种情况下,应该清楚的是,没有任何其他因素影响结果,对css文件的10个请求将导致它被发送到客户端(浏览器)10次.

好处

  • 内容总是新鲜的
  • 无需任何努力/管理

缺点

  • 最低效,内容总是转移

验证请求:10个请求

如果使用Last-ModifiedEtag,则还会有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
Run Code Online (Sandbox Code Playgroud)

对同一网址的后续请求如下所示:

$ 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
Run Code Online (Sandbox Code Playgroud)

请注意,没有正文,响应是304 Not Modified.这告诉客户端它已经拥有的内容(在本地缓存中)仍然是新鲜的.

这并不是说这是最佳方案.使用诸如chrome开发人员工具的网络选项卡之类的工具,您可以准确地查看请求需要多长时间,以及执行什么操作:

在此输入图像描述

由于响应没有正文,响应时间会少得多,因为要传输的数据较少.但是,仍然响应.还有就是仍然是所有连接到远程服务器的开销.

好处

  • 内容总是新鲜的
  • 只发送一个"完整"请求
  • 九个请求更加纤薄,只包含标题
  • 更高效

缺点

  • 仍然会发出最大数量的请求
  • 仍然会进行DNS查找
  • 仍然需要建立与远程服务器的连接
  • 不能脱机工作
  • 可能需要服务器配置

永久缓存:1个请求

如果没有etags,没有最后修改的标头,并且将来只有一个过期标头集 - 只有第一次访问url才会导致与远程服务器的任何通信.这是众所周知的?更好的前端性能的最佳实践.如果是这种情况,对于后续请求,客户端将从其自己的缓存中读取内容,而根本不与远程服务器通信.

这具有明显的性能优势,这对于延迟可能很大的移动设备尤其重要(温和地说).

好处

  • 效率最高,内容只转移一次

缺点

  • 必须更改URL 以防止现有访问者加载过时的缓存版本
  • 最需要设置/管理

不要使用查询字符串进行缓存清除

它是绕过客户端的缓存,网站使用查询参数.当内容更改(或者发布新版本的站点)时,将修改查询参数,因此在URL更改时将请求该文件的版本.与每次更改文件时重命名文件相比,这项工作更少/更方便,但是没有问题,

使用查询字符串可防止代理缓存,在下面的引用中,作者证明来自浏览器< - >代理缓存服务器< - >网站的请求不使用代理缓存:

加载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
Run Code Online (Sandbox Code Playgroud)

这里很清楚,第二个响应没有被代理服务:缓存响应标头说MISS,Date和Expires值改变,并且拖尾stevesouders.com访问日志显示两个命中.

这不应该掉以轻心 - 当访问位于世界另一端的物理网站时,响应时间可能非常慢.从位于路径上的代理服务器获得答案可能意味着网站之间的区别是否可用 - 在永久缓存资源的情况下,这意味着在使用验证请求的情况下,第一次加载网址的速度很慢意味着整个网站将是缓慢的.

而是版本控制资产

"最佳"解决方案是版本控制文件,以便每当内容发生变化时,网址也会发生变化.通常,这将作为构建过程的一部分自动化.

然而,近乎妥协的是实现重写规则,如

# ------------------------------------------------------------------------------
# | 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>
Run Code Online (Sandbox Code Playgroud)

通过这种方式foo.123.css,服务器处理请求foo.css- 这具有使用查询参数进行缓存清除的所有优点,但没有禁用代理缓存的问题.

  • "不要使用查询字符串进行缓存清除"是一个过时的2008概念.http://www.bizcoder.com/caching-resources-with-query-strings (3认同)