秋招复习计划-浏览器缓存

  |  

前言

来彻底了解一下浏览器缓存的策略

67



缓存的判断策略

浏览器对于所有请求资源的缓存处理有一套完整的机制,主要包含以下三个策略:

  • 存储策略:发生在收到请求后,用于决定是否缓存相应资源
  • 过期策略:发生在请求前,用于判断缓存是否过期
  • 协商测率:发生在请求中,用于判断缓存是否更新

具体的判断流程如下:

判断流程

判断流程会根据不同方式跳过一些流程

浏览器访问资源的方式主要有一下几种:

  • 地址栏回车
  • 链接跳转
  • 前进后退
  • 从收藏栏中打开链接
  • window.open打开新窗口
  • 刷新
  • 强制刷新

不同的访问方式,会从不同的缓存应用步骤判断开始

访问方式

webkit将资源分为两类:主资源和派生资源。主资源是地址栏输入的URL 请求返回的资源,派生资源是主资源中所引用的JS、CSS、图片等资源。

在Chrome下刷新,只有主资源的缓存应用方式如上图所示,派生资源的缓存应用方式与新标签打开类似,会判断缓存是否过期。

缓存基础

HTTP协议中与缓存有关的字段主要有以下10个。

缓存头部

缓存又分强缓存和弱缓存(协商缓存),它们二者的最主要区别在于获取资源时是否会请求服务器。

强缓存是在过期策略判断缓存并没有过期后应用的缓存,而协商缓存则是在协商协议生效后应用的缓存。弱缓存需要通过给服务器发送请求,服务器根据请求头部来判断是否符合协商缓存的策略。如果符合则服务器返回请求,不符合则返回资源

获取资源的形式 状态码 是否发送请求到服务器
强缓存 从缓存中取 200(from cache)
协商缓存 从缓存中取或从服务器取 304(not modified) 是,根据服务器返回决定是否采用缓存

Expires

Expires头部指定缓存的过期时间,为绝对时间,及某一时刻。参考本地时间进行对比,在指定时刻过后过期。

Expires头字段是响应头字段,格式如下Expires: Sat Oct 20 2018 00:00:00 GMT+0800 (CST)

下面用给定代码测试一下。

  1. 执行node cache-Expires.js,该脚本会给请求的资源设定Expires

    Expires1

  2. 访问地址http://localhost:1030/,查看Network,可以看到avatar.jpg图片的Expires值如下

    Expires2

  3. 由于我的本地时间已经超过了缓存有效期,所以avatar.jpg并不是从缓存中读取的,接下来我们修改代码,把过期时间延后

    Expires3

    就可以看到,avatar.jpg的读取是frome memory cache。

Cache-Control

Cache-Control用于指定资源的缓存机制,可以同时在请求头和响应头中设定,涉及到存储策略和过期策略。

Cache-Control的语法如下:Cache-Control: cache-directive,cache-directive。cache-directive,cache-directive为缓存指令,大小写不敏感,用逗号隔开。

总共有12个与HTTP缓存标准相关的指令,请求指令7种,响应指令9种。

cache指令

在请求头中的max-age

max-age在请求头中的主要应用为max-age=0,表示不使用缓存。Chrome和FireFox浏览器下的刷新操作就是在请求头上添加了max-age=0指令,表示不适用强缓存,但允许协商缓存。

max-age与Expires

max-age的优先级会高于Expires,如果同时设置max-age与Expires,Expires无效,max-age有效

no-cache和no-store

no-cache并不是指不缓存文件,no-store才是不缓存,no-cache表明跳过强缓存,强制进入协商策略

Pragma

HTTP1.0的字段,通常设置为Pragma:no-cache,作用与Cache-Control:no-cache相同。当在浏览器进行强刷(Comand + Shift + R / Ctrl + F5)或在NetWork面板内勾选禁用缓存(Disable Caches)时,会自动带上Pragma:no-cache和Cache-Control:no-cache,并且不会带上协商策略中所涉及的信息(下面介绍的If-Modified-Since/If-None-Match)。这是不会使用任何缓存,重新获取资源。

Last-Modified/If-Modified-Since/If-Unmodified-Since

Last-Modified用于标记请求资源的最后一次修改时间。语法格式为:Last-Modified: <day-name>,<day> <month> <year> <hour>:<minute>:<second> GMT,即GMT(格林尼治标准时间)。可用 new Date().toGMTString()获取当前GMT时间。由于Last-Modified只能精确到秒,因此不适合在一秒内多次改变的资源。

如果Expires,Cache-Control: max-age,或 Cache-Control:s-maxage都没有在响应头中出现,并且设置了Last-Modified时,那么浏览器默认会采用一个启发式的算法,即启发式缓存。通常会取响应头的Date_value - Last-Modified_value值的10%作为缓存时间。及当前日期减去最后一次修改日期的时间的百分之十

If-Modified-Since

返回的资源带有Last-Modified标识时,再次请求该资源,浏览器会自动带上If-Modified-Since,值为返回的Last-Modified值。请求到达服务器后,服务器进行判断,如果从上次更新后没有再更新,则返回304。如果更新了则重新返回资源。

If-Unmodified-Since

当资源在Last-Modified的时间之后没有进行修改,服务器返回请求的资源。如果发生了修改,返回412

ETag/If-Match/If-None-Match

ETag是请求资源在服务器的唯一标识,浏览器可以根据ETag值缓存数据。在再次请求时通过If-None-Match携带上次的ETag值,如果值不变,则返回304,如果改变你则返回新的内容。

If-Match判断逻辑逻辑与If-None-Match相反。服务器上没有任何资源的 ETag 属性值与这个首部中列出的相匹配的时候,服务器端会才返回所请求的资源,响应码为 200 。对于GET和 HEAD方法来说,当验证失败的时候,服务器端必须返回响应码 304 (Not Modified,未改变)

最后,ETag的优先级高于Last-Modified。当ETag和Last-Modified,ETag优先级更高,但不会忽略Last-Modified,需要服务端实现。

各种缓存方式的优缺点

优缺点

最佳实现

  1. 不要缓存HTML,避免缓存后用户无法及时获取到更新内容。
  2. 使用Cache-Control和ETag来控制HTML中所使用的静态资源的缓存。一般是将Cache-Control的max-age设成一个比较大的值,然后用ETag进行验证。
  3. 使用签名或者版本来区分静态资源。这样静态资源会生成不同的资源访问链接,不会产生修改之后无法感知的情况。

测试题

1
2
3
4
5
6
7
8
9
10
11
HTTP/1.1 200 OK

Cache-Control: no-cache

Content-Type: image/png

Last-Modified: Tue, 16 Oct 2018 11:42:28 GMT

Accept-Ranges: bytes

Date: Tue, 16 Oct 2018 15:57:21 GMT

当你第一次请求一个图片资源后返回的响应头部如上,那么:

  • 当刷新页面后,这个图片将如何二次加载
  • 当将Cache-Control设置为private,那么又将如何加载。

答案

对于第一问,由于Cache-Control设置为no-cache,所以缓存会立即过期,跳过强缓存,执行协商缓存,那么二次请求的时候,请求头会带有If-Modeified-Since字段和服务端进行验证,未改变返回304,改变返回200.

对于第二问,由于Cache-Control已经改变为private,那么资源仅在客户端缓存,缓存的有效时间为(Data-Last-Modified )*0.1,在这个时间内的二次加载将从缓存中加载,在这个事件后,将执行协商缓存策略

文章目录
  1. 1. 缓存的判断策略
  2. 2. 缓存基础
    1. 2.1. Expires
    2. 2.2. Cache-Control
    3. 2.3. Pragma
    4. 2.4. Last-Modified/If-Modified-Since/If-Unmodified-Since
    5. 2.5. ETag/If-Match/If-None-Match
  3. 3. 各种缓存方式的优缺点
  4. 4. 测试题