缓存普遍存在于咱们的平常上网过程当中。使用缓存主要有几个好处:web
一是可以减轻服务器端的访问压力;数组
二是使用本地缓存可以加快页面的载入速度,提高用户体验。浏览器
在了解如何使用缓存来优化咱们的web应用以前,咱们先来看看web缓存具体有哪些分类:缓存
浏览器能够将一些比较消耗带宽并且几乎不会变动的静态资源缓存在本地,当用户须要再次使用这部分资源(好比用户在点击浏览器中的页面前进或后退按钮等)时,就能够直接从浏览器缓存中加载,而不须要再向服务器发起请求。bash
典型表明就是反向代理服务器缓存,反向代理服务器大多数时候就是在分担服务器端的访问压力,能尽可能减小向源服务器发送请求就尽可能减小,能尽量地利用缓存下来的资源就尽量地利用。一些大型站点会使用CDN
,目的是为了让用户就近访问,加快页面的载入速度,而在每一个CDN节点一样也会缓存用户访问过的资源,所以也属于服务器端缓存的范畴。服务器
要实现浏览器和服务器对用户重复访问的资源进行缓存控制,主要有两种途径:优化
一种是经过设置 <meta>
标签来控制:ui
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="-1">
复制代码
注意上面两条指令的做用是不容许浏览器缓存当前页面以及页面上引用的资源,强制浏览器每次请求当前页面时都须要从服务器端获取最新版本。这种方式仅对部分浏览器有效,并且不影响代理服务器对该页面的缓存控制,缘由是由于代理服务器并不会去解析页面上的内容。spa
另一种应用更加普遍的方法就是经过 http 协议的头部字段进行缓存的控制。而经过 http 头部字段进行控制又能够从两个角度来控制缓存:分别是新鲜度(对应 Cache-Control
和 Expires
)和校验值(对应 Last-Modified
和 Etag
)。其实缓存控制就是在关注这样两个问题:一方面是能够缓存多长时间(新鲜度),另外一方面则是如何判断缓存失效(校验)。代理
Cache-Control
/ Expires
这一组头部字段均可以用来指定缓存的有效期,区别在于前者除了能够指定缓存有效期(经过设置max-age参数,该参数值和Expires具体含义还不相同,前者指定缓存时长,然后者指定缓存过时的时间点)以外,还能够实现更加精细的缓存控制功能;然后者只能单一地设置缓存的有效期。
Cache-Control 是一个通用首部,而且在请求头和响应头使用的参数还略微有些差别。下面就具体介绍一下 Cache-Control 能够设置的参数都有哪些以及它们所表明的含义(此处仅介绍出如今服务器端响应中的 Cache-Control 可能会用到的参数)。
max-age=<num>
: 前面提到过了,这里再也不赘述。单位:秒s-max-age=<num>
: 做用和 max-age 相似,区别在于该参数仅对提供共享缓存的公共代理服务器起做用no-store
:不容许客户端和缓存服务器对响应进行缓存,意味着每次都会从新向源服务器发起请求(注意不是条件请求)no-cache
:应用这个值时,客户端和缓存服务器在使用缓存资源以前须要向源服务器发起条件请求确认,相似于max-age=0,注意此时浏览器和缓存服务器是能够缓存响应的public
:此参数是对缓存服务器起做用的,表示容许向多个不一样的用户提供同一份缓存(共享缓存)private
:与public
恰好相反,表示当前缓存的内容仅能对当前用户提供Cache-Control 首部的值能够由多个参数组合而成,参数之间使用逗号隔开。
Expires
首部用于指定缓存失效的时刻,时间是以服务器上的时间为准。
服务器能够经过Last-Modified响应首部来指明当前访问资源最近一次修改是在何时,客户端在发送请求校验资源是否发生修改时,能够经过If-Modified-Since请求首部向服务器端确认资源在给定时间点以后是否发生更改,服务器能够根据比对资源的最近一次修改时间和If-Modified-Since首部指定的时间来决定返回304状态码仍是返回新的资源。
使用Last-Modified/If-Modified-Since比对文件修改时间的这套机制存在的问题就是:
由于Last-Modified指定的修改时间是精确到秒级的,若是服务器上的文件在一秒内发生屡次更改,单纯依靠文件修改时间就检测不到文件已经发生变化
若是文件在某个时间段内发生屡次更改,可是先后文件内容并无发生变化,这时依靠文件修改时间去判断文件已经发生修改也不合适
而经过Etag响应首部就可以解决上面提到的问题。经过对当前文件内容计算生成一个惟一标识,经过比对标识是否相同来判断文件内容是否发生变化。相比于比较文件修改时间,这种方式更加有效。客户端在发送条件请求时,会包含 If-None-Match
请求首部,来判断文件内容是否发生变化。
除了可使用上面提到的这些首部来控制缓存以外,另外还有一个古老的响应首部就是 Pragma
。Pragma 首部的值只有一个可选值就是 no-cache
,含义和 Cache-Control: no-cache 是同样的。可是 Pragma 优先级要高于 Cache-Control,而Cache-Control则又比Expires首部具备更高的优先级。
除了能够经过 http 首部来控制缓存以外,在浏览器中不一样的操做行为一样也会影响浏览器是否使用缓存。
当用户点击前进或后退按钮,不管服务器响应的Cache-Control是什么值(no-store
除外),浏览器都会直接使用硬盘中缓存的内容。
在Cache-Control/Expires指定的有效期内若是用户输入URL地址以后回车(包括点击页面的刷新按钮或者 F5
),此时浏览器会直接使用硬盘中的缓存内容(以下图),而不会向服务器发起请求。而此时若是缓存期限已过,而以前服务器响应中包含 Last-Modified/Etag 首部(通常服务器返回的响应都会包含这两个首部,不须要额外的配置),则会向服务器发起条件请求,若是服务器端内容没有发生更改,则会响应 304
状态码,提示浏览器缓存有效。
当点击 Ctrl+F5
时,即便缓存的资源依然有效(仍然在 Cache-Control 首部包含的 max-age 参数指定的期限以内),浏览器也会向服务器发起请求(注意此时的请求就不是条件请求了,而是强制从服务器获取最新的内容)。
文章中咱们主要探讨了如何经过 http 首部来控制浏览器端缓存,主要能够归纳为如下几点:
Cache-Control 能够精细地控制缓存,可是须要注意的一点是,它是在 HTTP/1.1 中才出现的,若是须要兼容旧版本,在指定缓存时长时能够和 Expires 首部一块儿搭配使用,若是要指定为 no-cache 则能够和 Pragma 首部一块儿使用
不一样的浏览器操做行为一样会影响浏览器是否使用本地缓存,有些行为(好比点击前进后退按钮)会直接从浏览器缓存中返回内容,有些行为(好比当缓存过时时点击刷新按钮等)则会致使浏览器发送条件请求确认资源是否更新
优先使用Etag/If-None-Match来校验资源是否有效