我在用我的网站资源caching的方法,并注意到大多数网站类似于我的使用查询string来覆盖caching(例如:/css/style.css?v=124942823)
后来,我注意到,每当我保存我的style.css文件,最后修改的标题“更新”,使查询string不必要的。
所以我想知道:
谢谢!
为什么这么多的网站使用“查询字符串”的方法,而不是让最后修改的头做它的工作?
更改查询字符串会更改网址,确保内容“新鲜”。
我应该取消最后修改的标题,只处理查询字符串?
不,尽管这几乎是正确的答案。
网上有三种基本的缓存策略:
为了说明这三点,请考虑以下情况:
用户首次访问网站,加载10页,离开。 每个页面加载相同的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未修改 。 这是告诉客户端,它已经拥有的内容(在本地缓存),该网址仍然是新鲜的。
这并不是说这是最佳的情况。 使用诸如chrome开发人员工具的网络选项卡之类的工具 ,您可以准确查看请求所需的时间和做了什么:
由于响应没有主体,所以响应时间会少得多,因为传输的数据较少。 但仍有回应。 而且还有连接到远程服务器的所有开销。
如果没有etags,没有最后修改的头文件,而且将来只有一个expires头文件 – 只有第一次访问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
在这里很明显,代理服务器没有提供第二个响应:高速缓存响应头文件说MISS,日期和过期值发生了变化,拖拽stevesouders.com访问日志显示两个命中。
这不应该掉以轻心 – 当访问位于世界另一端的网站时,响应时间可能非常缓慢。 从位于路径上的代理服务器获取答案可能意味着网站可用与否之间的差异 – 对于永久缓存的资源,这意味着网址的第一次加载速度很慢,在使用验证请求的情况下意味着整个网站将会不景气。
“最好的”解决方案是版本控制文件,这样当内容发生变化时,url也是如此。 通常这将作为构建过程的一部分自动化。
然而,近乎妥协的是实施一个重写规则,如
# ------------------------------------------------------------------------------ # | 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 <Ifmodulee mod_rewrite.c> RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpe?g|gif)$ $1.$3 [L] </Ifmodulee>
通过这种方式, foo.123.css
的请求被服务器处理为foo.css
– 这具有使用查询参数进行缓存清除的所有优点,但是没有禁用代理缓存的问题。
Last-Modified头在不同浏览器中的应用是不同的,但通常浏览器将发出一个条件GET请求,如果需要更新缓存,服务器必须响应。 例如,在Firefox中…
“Last-Modified”响应头可以用作弱验证器。 它被认为是微弱的,因为它只有1秒的分辨率。 如果响应中存在“Last-Modified”标头,则客户端可以发出“If-Modified-Since”请求标头来验证缓存文档。
当发出验证请求时,服务器可以忽略验证请求并以普通的200 OK进行响应,也可以返回304 Not Modified指示浏览器使用其缓存副本。 后者的响应也可以包含更新缓存文档到期时间的标题。
通过设置时间戳(或指纹),您可以明确地让浏览器知道何时需要更新其缓存,然后可以设置很长的到期时间。
值得注意的是rails资产管道( http://guides.rubyonrails.org/asset_pipeline.html )上的文档引用了查询字符串时间戳上指纹的三个优点:
有关缓存的更多详细信息和最佳做法: https : //developers.google.com/speed/docs/best-practices/caching