浏览器从输入到输出的过程与原理二之缓存

1. 浏览器缓存

浏览器缓存的知识是前端工程师必需要掌握的,由于这些知识直接影响到你的页面的用户体验,影响到你的页面的加载策略。接下来将要详细的讲述浏览器缓存的概念和原理,缓存的知识除了和浏览器有关,还涉及到HTTP协议。前端

1.1 概念

浏览器缓存(Browser Caching)是为了节约网络的资源加速浏览,浏览器在用户磁盘上对最近请求过的文档进行存储,当访问者再次请求这个页面时,浏览器就能够从本地磁盘显示文档,这样就能够加速页面的阅览。浏览器缓存主要有两类:缓存协商和强缓存。web

1.2 请求流程图

image

上图是浏览器第一次请求时发生过流程,浏览器显然不存在任何缓存数据,浏览器跳过校验缓存这一步,直接进入下一个流程,向网络发起请求,也就是上图中的[ 向web服务器发起请求 ]。算法

这个过程包含不少内容,将在后续的内容叙述。浏览器

image

从上面的请求流程图能够知道,浏览器缓存包含两种类型,即强缓存(也叫本地缓存)和协商缓存。缓存

强缓存

强缓存是与(cache-control和expires信息)有关的缓存。服务器

cache-control

Cache-Control 是最重要的规则。这个字段用于指定全部缓存机制在整个请求/响应链中必须服从的指令。这些指令指定用于阻止缓存对请求或响应形成不利干扰的行为。这些指令一般覆盖默认缓存算法。缓存指令是单向的,即请求中存在一个指令并不意味着响应中将存在同一个指令。网络

cache-control 定义是:Cache-Control = “Cache-Control” “:” cache-directive。前端工程师

网页的缓存是由HTTP消息头中的“Cache-control”来控制的,常见的取值有private、no-cache、max-age、must-revalidate等,默认为private。测试

表 1. 经常使用 cache-directive 值编码

Cache-directive

说明

public

全部内容都将被缓存(客户端和代理服务器均可缓存)

private

内容只缓存到私有缓存中(仅客户端能够缓存,代理服务器不可缓存)

no-cache

必须先与服务器确认返回的响应是否被更改,而后才能使用该响应来知足后续对同一个网址的请求。所以,若是存在合适的验证令牌 (ETag),no-cache 会发起往返通讯来验证缓存的响应,若是资源未被更改,能够避免下载。

no-store

全部内容都不会被缓存到缓存或 Internet 临时文件中

must-revalidation/proxy-revalidation

若是缓存的内容失效,请求必须发送到服务器/代理以进行从新验证

max-age=xxx (xxx is numeric)

缓存的内容将在 xxx 秒后失效, 这个选项只在HTTP 1.1可用, 并若是和Last-Modified一块儿使用时, 优先级较高

表 2 代表在不一样的情形下,浏览器是将请求从新发送到服务器仍是使用缓存的内容。

表 2. 对 cache-directive 值的浏览器响应

Cache-directive

打开一个新的浏览器窗口

在原窗口中单击 Enter 按钮

刷新

单击 Back 按钮

public

浏览器呈现来自缓存的页面

浏览器呈现来自缓存的页面

浏览器从新发送请求到服务器

浏览器呈现来自缓存的页面

private

浏览器从新发送请求到服务器

第一次,浏览器从新发送请求到服务器;此后,浏览器呈现来自缓存的页面

浏览器从新发送请求到服务器

浏览器呈现来自缓存的页面

no-cache/no-store

浏览器从新发送请求到服务器

浏览器从新发送请求到服务器

浏览器从新发送请求到服务器

浏览器从新发送请求到服务器

must-revalidation/proxy-revalidation

浏览器从新发送请求到服务器

第一次,浏览器从新发送请求到服务器;此后,浏览器呈现来自缓存的页面

浏览器从新发送请求到服务器

浏览器呈现来自缓存的页面

max-age=xxx (xxx is numeric)

在 xxx 秒后,浏览器从新发送请求到服务器

在 xxx 秒后,浏览器从新发送请求到服务器

浏览器从新发送请求到服务器

在 xxx 秒后,浏览器从新发送请求到服务器

Cache-Control是关于浏览器缓存的最重要的设置,由于它覆盖其余设置,好比 Expires 和 Last-Modified。另外,因为浏览器的行为基本相同,这个属性是处理跨浏览器缓存问题的最有效的方法。

Expires

Expires 头部字段提供一个日期和时间,响应在该日期和时间后被认为失效。失效的缓存条目一般不会被缓存(不管是代理缓存仍是用户代理缓存)返回,除非首先经过原始服务器(或者拥有该实体的最新副本的中介缓存)验证。(注意:cache-control max-age 和 s-maxage 将覆盖 Expires 头部。)

Expires 字段接收如下格式的值:“Expires: Sun, 08 Nov 2009 03:37:26 GMT”。若是查看内容时的日期在给定的日期以前,则认为该内容没有失效并从缓存中提取出来。反之,则认为该内容失效,缓存将采起一些措施。

不一样操做下不一样浏览器的响应。具体相关内容参见百度百科词条

协商缓存

协商缓存是与Last-Modified和Etag相关的缓存。

Last-Modified

在浏览器第一次请求某一个URL时,服务器端的返回状态会是200,内容是客户端请求的资源,同时有一个Last-Modified的属性标记此文件在服务器端最后被修改的时间。

Last-Modified格式相似这样:

Last-Modified : Fri , 12 May 2006 18:53:33 GMT

客户端第二次请求此URL时,根据HTTP协议的规定,浏览器会向服务器传送If-Modified-Since报头,询问该时间以后文件是否有被修改过:

If-Modified-Since : Fri , 12 May 2006 18:53:33 GMT

若是服务器端的资源没有变化,则自动返回 HTTP 304(Not Changed.)状态码,内容为空,这样就节省了传输数据量。当服务器端代码发生改变或者重启服务器时,则从新发出资源,返回和第一次请求时相似。从而保证不向客户端重复发出资源,也保证当服务器有变化时,客户端可以获得最新的资源。

Etag的概念

HTTP协议规格说明定义ETag为“被请求变量的实体值”。另外一种说法是,ETag是一个能够与Web资源关联的记号(token)。典型的Web资源能够是一个Web页,但也多是JSON或XML文档。服务器单独负责判断记号是什么及其含义,并在HTTP响应头中将其传送到客户端,如下是服务器端返回的格式:ETag:"50b1c1d4f775c61:df3"客户端的查询更新格式是这样的:If-None-Match : W / "50b1c1d4f775c61:df3"若是ETag没改变,则返回状态304而后不返回,这也和Last-Modified同样。测试Etag主要在断点下载时比较有用。

客户端请求一个页面(A)。 服务器返回页面A,并在给A加上一个ETag。 客户端展示该页面,并将页面连同ETag一块儿缓存。 客户再次请求页面A,并将上次请求时服务器返回的ETag一块儿传递给服务器。 服务器检查该ETag,并判断出该页面自上次客户端请求以后还未被修改,直接返回响应304(未修改——Not Modified)和一个空的响应体。

Etag的优点

一、有些URL是多语言的网页,相同的URL会返回不一样的东东。还有不一样的Session有不一样的Cookie也就有不一样的内容。这种状况下若是过 Proxy,Proxy就没法区分致使串门,只能简单的取消cache功能。Etag解决了这个问题,由于它能区分相同URL不一样的对象。

二、老的HTTP标准里有个Last-Modified+If-Modified-Since代表URL对象是否改变。Etag也具备这种功能,由于对象改变也形成Etag改变,而且它的控制更加准确。Etag有两种用法 If-Match/If-None-Match,就是若是服务器的对象和客户端的对象ID(不)匹配才执行。这里的If-Match/If-None- Match都能一次提交多个Etag。If-Match能够在Etag未改变时断线重传。If-None-Match能够刷新对象(在有新的Etag时返回)。

三、Etag中有种Weak Tag,值为 W/"xxxxx"。他声明Tag是弱匹配的,只能作模糊匹配,在差别达到必定阈值时才起做用。

四、Etag对于cache CGI页面颇有用。特别是论坛,论坛有办法为每一个帖子页面生成惟一的Etag,在帖子未改变时,查看话题属性比较Etag就能避免刷新帖子,减小CGI操做和网络传输。好比论坛中看帖就返回Etag,减小论坛负担。

五、Etag在不一样URL之间没有可比性,也就是不一样URL相同Etag没有特别意义。

Etag的原理

请求流程

Etag由服务器端生成,客户端经过If-Match或者说If-None-Match这个条件判断请求来验证资源是否修改。常见的是使用If-None-Match。请求一个文件的流程可能以下:

====第一次请求===

1.客户端发起 HTTP GET 请求一个文件;

2.服务器处理请求,返回文件内容和一堆Header,固然包括Etag(例如"2e681a-6-5d044840")(假设服务器支持Etag生成和已经开启了Etag)。状态码200。

====第二次请求===

1.客户端发起 HTTP GET 请求一个文件,注意这个时候客户端同时发送一个If-None-Match头,这个头的内容就是第一次请求时服务器返回的Etag:2e681a-6-5d044840

2.服务器判断发送过来的Etag和计算出来的Etag匹配,所以If-None-Match为False,不返回200,返回304,客户端继续使用本地缓存;

流程很简单,问题是,若是服务器又设置了Cache-Control:max-age和Expires呢,怎么办?

答案是同时使用,也就是说在彻底匹配If-Modified-Since和If-None-Match即检查完修改时间和Etag以后,服务器才能返回304.(不要陷入到底使用谁的问题怪圈)

Etag的做用

Etag 主要为了解决 Last-Modified 没法解决的一些问题。

一、一些文件也许会周期性的更改,可是他的内容并不改变(仅仅改变的修改时间),这个时候咱们并不但愿客户端认为这个文件被修改了,而从新GET。

二、某些文件修改很是频繁,好比在秒如下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改没法判断(或者说UNIX记录MTIME只能精确到秒)。

三、某些服务器不能精确的获得文件的最后修改时间;

为此,HTTP/1.1引入了 Etag(Entity Tags)。Etag仅仅是一个和文件相关的标记,能够是一个版本标记,好比说v1.0.0或者说"2e681a-6-5d044840"这么一串看起来很神秘的编码。可是HTTP/1.1标准并无规定Etag的内容是什么或者说要怎么实现,惟一规定的是Etag须要放在""内。

3.3 结束

关于缓存的内容到此告一段落,对于强缓存和协商缓存,不一样的浏览器和不一样的用户操做行为,都有产生不一样的请求操做,对于各个版本的浏览器都须要进行详细的兼容性分析。

相关文章
相关标签/搜索