浏览器缓存机制、http缓存头

来源:互联网 发布:淘宝客 部分退款 编辑:程序博客网 时间:2024/05/19 16:21

缓存与目的

重用已获取的资源能够有效的提升网站与应用的性能。Web 缓存能够减少延迟与网络阻塞,进而减少显示某个资源所用的时间。借助 HTTP 缓存,Web 站点变得更具有响应性。缓存作为加快页面加载速度的方法,可以说是必不可少的一个方法,如何能更好地运用缓存来服务客户,首先我们就得了解清楚缓存;

缓存流程图

先上一张从SegmentFault搬运来的缓存过程图
缓存流程图
从图中能很清楚的看出来,缓存是怎样的一个运行流程,接下来我们将一一介绍几种缓存机制;

强制缓存

对于强制缓存来说,http头部中会有两个字段来标明失效规则(Expires/Cache-Control)
- Expires:
HTTP/1.0的缓存机制,Expires的值是服务器返回的过期时间,在过期之前浏览器都可以直接在缓存里读取相应的文件,但Expires存在一个BUG,这个BUG就是,Expires对比的时间是客户端的时间,也就是说,我们只要设置自己电脑的时间超过Expires的值就会被判定为相应的资源已经过期需要重新请求,所以可能会导致差错;优点是Expires的设置非常的简洁明了就是一个时间,示例:Expires: Thu, 01 Dec 1994 16:00:00 GMT
- Cache-Control:
Cache-Control是HTTP/1.1的产物,在request header与response header中都支持这个属性,值得注意的是,缓存指令是单向的, 这意味着在请求设置的指令,在响应中不一定包含相同的指令。
接下来来看一看Cache-Control的命令有哪些,作用都是什么:
- 请求指令与响应指令

Cache-Control: max-age=<seconds>Cache-Control: max-stale[=<seconds>]Cache-Control: min-fresh=<seconds>Cache-control: no-cache Cache-control: no-storeCache-control: no-transformCache-control: only-if-cached    
Cache-control: must-revalidateCache-control: no-cacheCache-control: no-storeCache-control: no-transformCache-control: publicCache-control: privateCache-control: proxy-revalidateCache-Control: max-age=<seconds>Cache-control: s-maxage=<seconds> 

可缓存性指令

  • 【public】:表明响应可以被任何对象(包括:发送请求的客户端,代理服 务器,等等)缓存。
  • 【private】:表明响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它)。
  • 【no-cache】:强制所有缓存了该响应的缓存用户,在使用已存储的缓存数据前,发送带验证器的请求到原始服务器
  • 【only-if-cached】:表明如果缓存存在,只使用缓存,无论原始服务器数据是否有更新。

过期指令:

  • max-age:设置缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒)。与Expires相反,时间是相对于请求的时间。所以避免了Expires的BUG;
  • min-fresh:表示客户端希望在指定的时间内获取最新的响应。

重新验证和重新加载:

  • must-revalidate:缓存必须在使用之前验证旧资源的状态,并且不可使用过期资源。(跟英文名一个意思,必须重校验)
  • proxy-revalidate:与must-revalidate作用相同,但它仅适用于共享缓存(例如代理),并被私有缓存忽略。

其他:

  • no-store:缓存不应存储有关客户端请求或服务器响应的任何内容。
  • no-transform:不得对资源进行转换或转变,Content-Encoding, Content-Range, Content-Type等HTTP头不能由代理修改

示例:

  • 禁止缓存
    缓存中不得存储任何关于客户端请求和服务端响应的内容。每次由客户端发起的请求都会下载完整的响应内容。
Cache-Control: no-storeCache-Control: no-cache, no-store, must-revalidate
  • 缓存静态资源
Cache-Control:public, max-age=31536000
  • 强制确认缓存
    此方式下,每次有请求发出时,缓存会将此请求发到服务器(该请求应该会带有与本地缓存相关的验证字段),服务器端会验证请求中所描述的缓存是否过期,若未过期(返回304),则缓存才使用本地缓存副本。
Cache-Control: no-cache

协商缓存OR对比缓存

需要进行比较判断是否可以使用,浏览器第一次发送请求后,服务器返回一个缓存标识,在第二次请求的时候发送这个缓存标识,服务器对比,如果判断相同后返回304状态吗,浏览器就可以使用缓存数据了;在成功的情况下大家都只有http头部信息;
关于这里的缓存标识存在两种类型,就是

Last-Modified/If-Modified-Since:

在服务器返回相应资源的时候在头部信息当中带上Last-Modified属性告诉浏览器,这个资源最后的修改时间,浏览器再次请求的时候会发送头部信息带上If-Modified-Since属性值为上一次服务器给出的Last-Modified,服务器进行匹配,匹配成功则说明资源没有更改返回304状态码,如果发现资源的修改时间大于If-Modified-Since则说明资源被改动过了,那么就会返回完整的资源和200状态码,并在头部信息中返回Last-Modified属性,浏览器也会更新相应的资源状态,在下次的If-Modified-Since中使用上一次服务器返回的Last-Modified值;

Etag/If-None-Match:

Etag是实体标签(Entity Tag)的缩写,是服务器资源的唯一标识符。在资源的各个生命周期中,它都具有不同的值,用于标识出资源的状态。当资源发生变更时,如果其头信息中一个或者多个发生变化,或者消息实体发生变化,那么ETag也随之发生变化。大概的服务器与浏览器的Etag/If-None-Match与Last-Modified/If-Modified-Since相同。
需要注意的点是:
1. Etag/If-None-Match的优先级高于Last-Modified/If-Modified-Since
2. 如果内容发生了变化,使用ETag有助于防止资源的同时更新相互覆盖(空中碰撞)
3. Last-Modified 标注的最后修改时间只能精确到秒,如果有些资源在一秒之内被多次修改的话,他就不能准确标注文件的新鲜度而Etag能做到
4. 语法,强弱校验器

ETag: W/"<etag_value>"ETag: "<etag_value>"

‘W/’(大小写敏感) :表示使用弱验证器。 弱验证器很容易生成,但不利于比较。 强验证器是比较的理想选择,但很难有效地生成。 相同资源的两个弱Etag值可能语义等同,但不是每个字节都相同。
etag_value:实体标签唯一地表示所请求的资源。 它们是位于双引号之间的ASCII字符串(如“675af34563dc-tr34”)
5.Etag并没有规范的生成方式,ETag值可以是唯一标识资源的任何东西,如持久化存储中的某个资源关联的版本、一个或者多个文件属性,实体头信息和校验值,也可以计算实体信息的散列值。有时候计算Etag的代价很大(哈希算法),有时候代价很小,所以就需要考虑在代价很大的时候通常将计算出的值保存下来,而在计算代价小的时候则通过每次去重新计算。

SO,很明显在协商缓存中,Etag的代价比Last-Modified/If-Modified-Since大,但是更精确,Etag的应用范围也更广,在项目中根据情景去使用了;

另外关于强缓存与协商缓存应该是并存公用的,浏览器会先检查强缓存,当强缓存命中的时候就会直接去加载资源,没有命中的情况下会进行协商缓存;

最后

在缓存当中,我们应该去缓存那些静态资源和不经常改变的资源,例如:Logo和商标图像、普通的不变化的图像、CSS样式表、普通的Javascript文件、可下载的内容、媒体文件等,千万不要去缓存经常变化的内容和用户的敏感信息(虽然缓存通常对于跨域页面是不可以共享的)

OK,如果有什么地方不对和补充,就评论吧(●’◡’●)