您的位置:首页 > 其它

浏览器缓存机制详解

2013-12-16 09:17 309 查看
浏览器的缓存机制,主要指由 HTTP协议
定义的缓存机制
。但也有非HTTP协议定义的缓存机制,如HTML Meta 标签,但所有缓存代理服务器都不支持,因为代理不解析HTML内容本身。

下主要介绍HTTP协议定义的缓存机制


Expires策略(HTTP
1.0)


Cache-control策略

Cache-Control 用于指定缓存控制Cache-Control的选择更多,设置更细致,优先级高于Expires

Public —— 指示该响应可以被共享缓存缓存。
Private ——指示该响应只能作为私有缓存。

no-cache —— 指示请求或响应消息
no-store ——  在请求消息中发送将使得请求和响应消息都不使用缓存。
max-age —— 指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。
min-fresh —— 指示客户机可以接收响应时间小于当前时间加上指定时间的响应。
max-stale —— 指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。



Last-Modified/If-Modified-Since

Last-Modified/If-Modified-Since要配合Cache-Control使用。

若资源改动过,则响应HTTP 200;若资源无修改,则响应HTTP
304 ,告知浏览器继续使用cache并更新缓存。



Etag/If-None-Match

Etag/If-None-Match也要配合Cache-Control使用。


既生Last-Modified何生Etag?

HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:

l  Last-Modified标注的最后修改只精确到秒级,如果某文件在1秒内,被修改多次,将不能准确标注文件的修改时间

l  如果某文件会被定期生成,但有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存

l  有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形

Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304


用户行为与缓存

浏览器缓存行为还有用户的行为有关!

用户操作
Expires/Cache-Control
Last-Modified/Etag
地址栏回车
有效
有效
页面链接跳转
有效
有效
新开窗口
有效
有效
前进、后退
有效
有效
F5刷新
无效
有效
Ctrl+F5刷新
无效
无效
缓存的处理流程



处理流程图,如上所示,下面分步骤具体介绍:

1)请求处理

用户发起一个HTTP请求,缓存获取到URL,根据URL查找是否有匹配的副本,这个副本可能在内存中,也可能在本地磁盘。

2) 新鲜度检测

如果缓存中存在所请求资源的副本,则进行新鲜度检测,检查这个副本有没有过期,如果没有过期,直接使用。如果已经过期,则进行再验证。

3)服务器再验证

缓存中的文档过期了并不代表他和服务器上的不一样,所以这个时候就需要问问服务器,过期的这段时间里这个文档到底有没有改变。如果改变了,缓存就会获取一份新的文档副本,然后发送给客户端。如果没有改变,缓存只需要获取新的首部,包括一个新的过期时间,并对缓存中的首部更新。

4)创建响应并返回

我们希望缓存看起来就像是来自原始服务器一样,缓存将已缓存的服务器响应首部作为响应首部,发送给客户端。

保质期的实现

HTTP中,通过 Cache-Control 首部和 Expires 首部为文档指定过期时间,通过对过期时间的判断,缓存就可以知道文档是不是在保质期内。Expires 首部和 Cache-Control:max-age 首部都是来告诉缓存文档有没有过期,为什么需要两个响应首部来做这件简单的事情了?其实这一切都是历史原因,Expires首部是HTTP 1.0中提出来的,因为他使用的是绝对日期,如果服务端和客户端时钟不同步的话(实际上这种情况非常常见),缓存可能就会认为文档已经过了保质期。

HTTP 1.1为了修正这个问题,引入了Cache-Control:max-age首部,这个首部使用相对时间来控制保质期,让一切变得更加合理。

服务器再验证

HTTP中,使用两个请求首部来完成这个功能:If-Modified-Sice 和 If-None-Match。为啥又要两个首部来完成这个功能了?答案还是因为历史的原因。一开始使用 If-Modified-Sice:<date>首部,date是上一次缓存文件时,响应中Last-Modified首部的值。

客户端拿着这个值,问服务器,这段时间内文件有没有修改过?服务器看了看这个文件的修改时间,如果没有修改过,会返回一个304 Not Modified的响应;如果修改过,把最新的文件返回给客户端。后来,人们发现这样有问题,因为就算修改时间变化了,文档也不一定发生改变!于是乎,就有了 If-None-Match:<tag>首部,tag是上一次缓存文档时,响应中Etag的值,Etag是一种唯一标识资源的方式。

试探性过期

如果响应中既没有Cache-Control:max-age首部又没有Expires首部,缓存可以计算出一个试探性最大使用期。这东西打个比方就是缓存会根据响应的Last-Modified来决定这文档靠不靠谱,需不需要再验证,如果Last-Modified中的日期是很早之前,那缓存就认为这文档挺靠谱,近期之内应该不会变化;如果Last-Modified中的日期是最近几天,那缓存可能就认为这文档可能经常改变,不靠谱。当然这么粗略的判断想想就知道不严谨,所以我们一定要设置Expires首部和Cache-Control首部。

写在最后

在chrome上为了保证文件安全,不信任缓存过期时间的设定,每次请求时都会询问服务器(再验证)。

原文地址:http://sojuker.blog.163.com/blog/static/13879087920121123113116655/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: