深入浏览器缓存

284 阅读5分钟

缓存是一种保存资源副本并在下次请求时直接使用该副本的技术.

现在的网站,不管是 PC 端还是移动端,各种请求几十个甚至上百个,每个请求每次都重新请求的话,用户等待时间(白屏)变长,用户体验会急剧下降,同时服务器压力和网络带宽都将面临严重的考验. 浏览器缓存可以大幅度提升 Web 应用的加载速度并降低服务器的压力,减少冗余数据传输,减少宽带.

HTTP 缓存机制分为两种,客户端缓存(私有缓存,浏览器缓存)和服务端缓存(共享缓存),而服务端缓存又分为 代理服务器缓存(例:CDN 服务)和反向代理服务器缓存(例:Nginx反向代理服务).这里主要是讨论浏览器缓存.


使用浏览器缓存的优点: 1.缓解网络瓶颈的问题,大量减少网络请求,将网络资源让给其他请求,同时降低原始服务器压力,减少宽带,节约资源 2.获取资源的耗时更短了,提升了性能,提示用户体验,并且在弱网等情况下效果更为显著.

对于网站来说,浏览器缓存是达到高性能的重要组成部分。


浏览器缓存整体缓存逻辑:


浏览器缓存逻辑细节:

浏览器对于请求资源,拥有一系列成熟的缓存策略. 按照发生的时间顺序分别为存储策略,过期策略,协商策略. 存储策略发生在收到请求响应后,用于决定是否缓存相应资源;过期策略发生在请求前,用于判断缓存是否过期;协商策略发生在请求中,用于判断缓存资源是否更新.

浏览器缓存都是通过http请求头部进行控制的,主要标签如下:


结合实际情况查看

Tips: 可以使用express的静态文件托管,配合chrome查看真实情况.express.static(root, [options]),options中可以配置缓存相关参数(参见:http://www.expressjs.com.cn/4x/api.html#express.static).

当浏览器请求资源时,会默认将资源存入缓存中,当第一请求的时候会在内存和硬盘中同时备份文件,以便下次重复利用资源。当用户刷新页面,如果缓存的资源没有过期,那么直接从内存中读取并加载.当用户关闭页面后,当前页面缓存在内存中的资源被清空.当用户再一次访问页面时,如果资源文件的缓存没有过期,那么将从本地磁盘进行加载并再次缓存到内存之中。

首次请求时:

Cache-Control是最高级的,会覆盖其他设置,并且可以设置复合规则,此时客户端总是采用最保守的缓存策略. Cache-Control 可以设置很多值,建议翻阅 MDN 文档.


缓存未过期:

强缓存:如果没有过期那么直接从本地缓存读取,不会产生http请求.

服务器可以通过在响应头部使用expires 和 cache-control 设置一个有效的过期时间,当浏览器再次请求资源时会判断本地缓存是否已过期. 如果 Expires, Cache-Control: max-age, 或 Cache-Control:s-maxage 都没有在响应头中出现, 并且也没有其它缓存的设置, 那么浏览器默认会采用一个启发式的算法, 通常会取响应头的 Date_value - Last-Modified_value 值的10%作为缓存时间.

from memory cache代表使用内存中的缓存,from disk cache则代表使用的是硬盘中的缓存,浏览器读取缓存的顺序为先memory,后disk.浏览器会在js和图片等文件解析执行后直接存入内存缓存中,那么当刷新页面时只需直接从内存缓存中读取(from memory cache);而css文件则会存入硬盘文件中,所以每次渲染页面都需要从硬盘读取缓存(from disk cache)。

强制缓存优先于协商缓存进行,若强制缓存(Expires和Cache-Control)生效则直接使用缓存,若不生效则进行协商缓存(Last-Modified / If-Modified-Since和Etag / If-None-Match),协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么代表该请求的缓存失效,重新获取请求结果,再存入浏览器缓存中;生效则返回304,继续使用缓存.


缓存过期

若缓存过期,则发生缓存协商,缓存协商策略用于重新验证缓存资源是否有效,有效对话存在若缓存,是在协商策略后应用的缓存

缓存已过期,但是文件未被修改:

缓存已过期且文件已被修改:

其他:

1.有时需要始终获最新的资源是可以在 url 上带上动态参数 例如:时间戳(timestamp)
2.勾选disable cache时,或强制刷新 (Ctrl + F5)时浏览器不使用缓存,此时浏览器自动带上了2个字段: Pragma:no-cache Cache-Control: no-cache
3.必要时可以通过html标签,或JS禁用缓存
4.关于缓存控制的请求头较多,建议翻阅 MDN 文档

实际使用

实际使用中,对于频繁变动的资源,首先需要使用Cache-Control: no-cache 使浏览器每次都请求服务器,然后配合 ETag 或者 Last-Modified 来验证资源是否有效; 不常变化的资源,给它们的 Cache-Control 配置一个很大的 max-age=31536000,而为了解决更新的问题,就在文件名(或者路径)中添加 hash, 版本号等动态字符,之后更改动态字符,从而达到更改引用 URL 的目的,让之前的强制缓存失效.例如:webpack 打包加上hash 值,加载指定版本的jQuery.

参考:

    1.https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Caching_FAQ
    2.http://feg.netease.com/archives/680.html
    3.http://louiszhai.github.io/2017/04/07/http-cache/
    4.https://imweb.io/topic/5795dcb6fb312541492eda8c
    5.https://segmentfault.com/a/1190000007317481
    6.https://www.jianshu.com/p/54cc04190252

很久没有写文章了,若存在不对的对方,请指正.谢谢!