HTTP 缓存
从网络上加载资源是非常缓慢且浪费带宽的,所以,要是能将资源缓存起来就好了!
幸运的是,所有的浏览器都实现了HTTP缓存,我们要做的只是设定服务器响应的头部就行了!
当服务器响应的时候,总是包含HTTP头部,HTTP头部包含的信息有content-type, length, caching directives, validation token,等.
上例中,服务器返回了1024字节的响应,告诉浏览器缓存120秒,提供了一个验证令牌(“x234dff”)可以在响应过期之后来判别资源是否改变。
使用 ETags鉴别已缓存的资源
- 验证令牌(validation token)是在HTTP 头部中用ETag表示。
- 验证令牌允许资源更新检查
当响应超过120秒之后过期了,我们是不是重新下载资源呢?不需要!因为在响应返回的时候生成了一个随机的数字,也就是验证令牌,相当于HTTP响应的ID,用来鉴别http响应,所以如下所示,当我们再次发送请求的时候,会发送上一次响应个验证令牌,用If-None-Match字段表示,检查响应是否相同,如果响应相同,那么浏览器就不会再次下载资源。所以,所有我们需要做的就是检查你的服务器文档是否允许听过Etag令牌。
Remember
- Tip: HTML5 Boilerplate 工程包含了 sample configuration files ,对于主流的服务器提供了详细的设置说明和例子。
Cache-Control字段
- 所有的资源通过Cache-Control HTTP 头部,定义了自己的缓存策略
- Cache-Control表明了谁缓存响应,在怎样的情况下缓存响应以及缓存多久
Remember
- Cache-Control 头部是在HTTP/1.1中定义的,并且重写了之前头部的一些字段(例如,Expires),所有的现代浏览器都支持Cache-Control,所以我们非常需要它
“no-cache” 和 “no-store”
“no-cache”表明在发送相同的url时,如果已存在验证令牌,还是会再次请求服务器一次,进行一次验证,但是不会进行资源的再次下载。
“no-store” 简单的表明资源不会被缓存,所以每一次请求都会下载一次资源。
“public” vs. “private”
如果响应被标记为 “public”那么响应可以被缓存,即使响应存在HTTP身份验证要求,即使响应的状态不是可缓存的。大多数的情况,”public“不是必须的,因为一旦使用了表明缓存事件的字段(例如max-age)就暗示了响应是可缓存的。
相反, “private” 表明可缓存,但是只是针对单个用户,例如一个HTML页面可以被用户的浏览器缓存,但是不可以被CDN缓存。
“max-age”
"max-age"表明了响应的响应的资源可以被再次使用的时间。- 例如. “max-age=60”表明了资源可以被缓存并且在下一个60秒内可以被再次使用。
定义最佳Cache-Control策略
理想状况下,你应该尽可能的保存多的资源,并且给每个资源设置较长的max-age 并且每个响应都要有一个验证令牌!
Cache-Control directives | Explanation |
---|---|
max-age=86400 | Response can be cached by browser and any intermediary caches (i.e. it is "public") for up to 1 day (60 seconds x 60 minutes x 24 hours) |
private, max-age=600 | Response can be cached by the client’s browser only for up to 10 minutes (60 seconds x 10 minutes) |
no-store | Response is not allowed to be cached and must be fetched in full on every request. |
According to HTTP Archive, amongst the top 300,000 sites (by Alexa rank), nearly half of all the downloaded responses can be cached by the browser, which is a huge savings for repeat pageviews and visits! Of course, that doesn’t mean that your particular application will have 50% of resources that can be cached: some sites can cache 90%+ of their resources, while others may have a lot of private or time-sensitive data that can’t be cached at all.
并不是缓存率越高,网站就越好,因为私有亦或对时间敏感的数据时不能被缓存的!
监听你的网站上哪些资源是可以被缓存的,并设置合理的max-age.
更新已缓存的数据
- 本地化已经缓存的数据允许我们使用,直到其“过期”
- 在URL中嵌入一个文件内容fingerprint允许客户端强制下载最新版本的资源。
- 为了最优的表现,每个应用需要定义它们自己的缓存等级。Each application needs to define its own cache hierarchy for optimal performance
例如我们更新了css文件,但是浏览器缓存了没有更新的css文件,并且缓存的css文件木有过期,我们想让浏览器加载最新的css文件,怎么办?我们除了改变资源加载的url没有任何办法。
我们可以在文件名中加入用户自定义的文件id,亦或版本号——例如e.g. style.x234dff.css,来让资源重新加载。
解释上面的代码:
- HTML文件标价了no-cache表明每一次url请求时都将进行检查并下载最新版本的资源。我们在css和javascript文件中都加入了文件的fingerprint,所以,如果css和js文件内容有所改变的话,文件名也会改变,url就会改变,html就会自动下载最新的资源。
- css文件可以被浏览器和中间商(例如CDN)缓存,我们设置css周期为1年,我们可以设置更久,因为一旦文件内容有所改变,文件会姿容加载。
- js文件只能被浏览器缓存,cdn等中间商不能缓存。
- 图片命名没有任何的版本号亦或fingerprint添加,并且设置缓存为1年。
缓存优化清单
- 同样的资源使用一样的url: 如果一样的资源但是用不同个url来加载的话,同样的资源将会下载多次!
- 确保服务器提供了验证令牌(ETag): 资源没有改变时,验证令牌减少了资源下载次数。
- 确认哪些资源可以被中间商缓存: 对所有用户都可以相同的资源可以使用例如cdn等中间商缓存
- 为每个资源设置最佳的缓存周期: 不同的资源有不同的刷新请求,所以,为每个资源设置最佳的缓存周期。
- 分离缓存文件: 一些资源更新频繁,比如js文件中的函数亦或css中的某些样式。可以将这些常更新的内容在大文件中分离出来,成为单独的文件,这样可以让剩余的不常更新的文件缓存更久,并且让更新受重新获取文件时,文件大小最小。