美文网首页让前端飞Vue
HTTP缓存机制及原理

HTTP缓存机制及原理

作者: alex夏夜 | 来源:发表于2019-03-01 16:41 被阅读1次

    首先了解HTTP报文

    HTTP报文就是浏览器和服务器间通信时发送及响应的数据块。
    浏览器向服务器请求数据,发送请求(request)报文;服务器向浏览器返回数据,返回响应(response)报文。
    报文信息主要分为两部分
    1.包含属性的首部(header)--------------------------附加信息(cookie,缓存信息等)与缓存相关的规则信息,均包含在header中
    2.包含数据的主体部分(body)-----------------------HTTP请求真正想要传输的部分

    接下来的内容中我们将通过以下几个部分来探讨浏览器缓存机制:

    • 缓存位置

    • 缓存策略

    • 实际场景应用缓存策略

    缓存位置

    从缓存位置上来说分为四种,并且各自有优先级,当依次查找缓存且都没有命中的时候,才会去请求网络.

    1.Service Worker
    2.Memory Cache
    3.Disk Cache
    4.Push Cache
    5.网络请求

    Service Worker

    Service Worker 的缓存与浏览器其他内建的缓存机制不同,它可以让我们自由控制缓存哪些文件、如何匹配缓存、如何读取缓存,并且缓存是持续性的。

    当 Service Worker 没有命中缓存的时候,我们需要去调用 fetch 函数获取数据。也就是说,如果我们没有在 Service Worker 命中缓存的话,会根据缓存查找优先级去查找数据。但是不管我们是从 Memory Cache 中还是从网络请求中获取的数据,浏览器都会显示我们是从 Service Worker 中获取的内容。

    Memory Cache

    Memory Cache 也就是内存中的缓存,读取内存中的数据肯定比磁盘快。但是内存缓存虽然读取高效,可是缓存持续性很短,会随着进程的释放而释放。 一旦我们关闭 Tab 页面,内存中的缓存也就被释放了。

    当我们访问过页面以后,再次刷新页面,可以发现很多数据都来自于内存缓存.


    从内存中读取缓存

    那么既然内存缓存这么高效,我们是不是能让数据都存放在内存中呢?

    先说结论,这是不可能的。首先计算机中的内存一定比硬盘容量小得多,操作系统需要精打细算内存的使用,所以能让我们使用的内存必然不多。内存中其实可以存储大部分的文件,比如说 JSS、HTML、CSS、图片等等。但是浏览器会把哪些文件丢进内存这个过程就很玄学了,我查阅了很多资料都没有一个定论。

    当然,我通过一些实践和猜测也得出了一些结论:

    • 对于大文件来说,大概率是不存储在内存中的,反之优先
    • 当前系统内存使用率高的话,文件优先存储进硬盘

    Disk Cache

    Disk Cache 也就是存储在硬盘中的缓存,读取速度慢点,但是什么都能存储到磁盘中,比之 Memory Cache 胜在容量和存储时效性上。

    在所有浏览器缓存中,Disk Cache 覆盖面基本是最大的。它会根据 HTTP Herder 中的字段判断哪些资源需要缓存,哪些资源可以不请求直接使用,哪些资源已经过期需要重新请求。并且即使在跨站点的情况下,相同地址的资源一旦被硬盘缓存下来,就不会再次去请求数据。

    Push Cache

    Push Cache 是 HTTP/2 中的内容,当以上三种缓存都没有命中时,它才会被使用。并且缓存时间也很短暂,只在会话(Session)中存在,一旦会话结束就被释放。

    Push Cache 在国内能够查到的资料很少,也是因为 HTTP/2 在国内不够普及,但是 HTTP/2 将会是日后的一个趋势。这里推荐阅读 HTTP/2 push is tougher than I thought 这篇文章,但是内容是英文的,我翻译一下文章中的几个结论,有能力的同学还是推荐自己阅读

    • 所有的资源都能被推送,但是 Edge 和 Safari 浏览器兼容性不怎么好
    • 可以推送 no-cache 和 no-store 的资源
    • 一旦连接被关闭,Push Cache 就被释放
    • 多个页面可以使用相同的 HTTP/2 连接,也就是说能使用同样的缓存
    • Push Cache 中的缓存只能被使用一次
    • 浏览器可以拒绝接受已经存在的资源推送
    • 你可以给其他域名推送资源

    网络请求

    如果所有缓存都没有命中的话,那么只能发起请求来获取资源了。

    那么为了性能上的考虑,大部分的接口都应该选择好缓存策略,接下来我们就来学习缓存策略这部分的内容。

    缓存策略

    强缓存

    用户发送的请求,直接从客户端缓存中获取,不发送请求到服务器,不与服务器发生交互行为。

    协商缓存(对比缓存)

    用户发送的请求,发送到服务器后,由服务器判定是否从缓存中获取资源。

    两者共同点:客户端获得的数据最后都是从客户端缓存中获得。

    两者的区别:从名字就可以看出,强缓存不与服务器交互(除第一次),而协商缓存则需要与服务器交互。

    细说强缓存


    从上文我们得知,强制缓存,在缓存数据未失效的情况下,可以直接使用缓存数据,那么浏览器是如何判断缓存数据是否失效呢?
    我们知道,在没有缓存数据的时候,浏览器向服务器请求数据时,服务器会将数据和缓存规则一并返回,缓存规则信息包含在响应header中。对于强制缓存来说,响应header中会有两个字段来标明失效规则(Expires/Cache-Control)使用chrome的开发者工具,可以很明显的看到对于强制缓存生效时,网络请求的情况。

    Cache-Control
    Cache-Control 是最重要的规则。常见的取值有private、public、no-cache、max-age,no-store,默认为private。
    private: 客户端可以缓存
    public: 客户端和代理服务器都可缓存(前端的同学,可以认为public和private是一样的)
    max-age=xxx: 缓存的内容将在 xxx 秒后失效
    no-cache: 指定不缓存响应,表明资源不进行缓存。但是设置了no-cache之后并不代表浏览器不缓存,而是在缓存前要向服务器确认资源是否被更改。因此有的时候只设置no-cache防止缓存还是不够保险,还可以加上private指令,将过期时间设为过去的时间.
    s-maxage: 只用于共享缓存,比如CDN缓存(s -> share)。与max-age 的区别是:max-age用于普通缓存,
    而s-maxage用于代理缓存。如果存在s-maxage,则会覆盖max-age 和 Expires.
    no-store: 所有内容都不会缓存,强制缓存,协商缓存都不会触发


    图中Cache-Control仅指定了max-age,所以默认为private,缓存时间为31536000秒(365天)
    也就是说,在365天内再次请求这条数据,都会直接获取缓存数据库中的数据,直接使用。
    1) 查看是否有cache-control 的max-age / s-maxage , 如果有,则用服务器时间date值 + max-age/s-maxage 的秒数计算出新的过期时间,将当前时间与过期时间进行比较,判断是否过期
    2)查看是否有cache-control 的max-age / s-maxage,则用expires 作为过期时间比较

    所以判断缓存是否过期步骤是:
    1) 查看是否有cache-control 的max-age / s-maxage , 如果有,则用服务器时间date值 + max-age/s-maxage 的秒数计算出新的过期时间,将当前时间与过期时间进行比较,判断是否过期
    2)查看是否有cache-control 的max-age / s-maxage,则用expires 作为过期时间比较

    细说协商缓存(对比缓存)


    协商缓存,顾名思义,需要进行比较判断是否可以使用缓存。
    浏览器第一次请求数据时,服务器会将缓存标识与数据一起返回给客户端,客户端将二者备份至缓存数据库中。
    再次请求数据时,客户端将备份的缓存标识发送给服务器,服务器根据缓存标识进行判断,判断成功后,返回304状态码,通知客户端比较成功,可以使用缓存数据。

    第一次访问:



    第二次访问



    通过两图的对比,我们可以很清楚的发现,在对比缓存生效时,状态码为304,并且报文大小和请求时间大大减少。
    原因是,服务端在进行标识比较后,只返回header部分,通过状态码通知客户端使用缓存,不再需要将报文主体部分返回给客户端。

    对于对比缓存来说,缓存标识的传递是我们着重需要理解的,它在请求header和响应header间进行传递,一共分为两种标识传递,接下来,我们分开介绍。

    Last-Modified / If-Modified-Since

    Last-Modified:服务器在响应请求时,告诉浏览器资源的最后修改时间。



    If-Modified-Since:
    再次请求服务器时,通过此字段通知服务器上次请求时,服务器返回的资源最后修改时间。
    服务器收到请求后发现有头If-Modified-Since 则与被请求资源的最后修改时间进行比对。
    若资源的最后修改时间大于If-Modified-Since,说明资源又被改动过,则响应整片资源内容,返回状态码200;
    若资源的最后修改时间小于或等于If-Modified-Since,说明资源无新修改,则响应HTTP 304,告知浏览器继续使用所保存的cache。



    ================================================================================

    Etag / If-None-Match(优先级高于Last-Modified / If-Modified-Since)

    Etag:
    服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)。



    If-None-Match:
    再次请求服务器时,通过此字段通知服务器客户段缓存数据的唯一标识。
    服务器收到请求后发现有头If-None-Match 则与被请求资源的唯一标识进行比对,
    不同,说明资源又被改动过,则响应整片资源内容,返回状态码200;
    相同,说明资源无新修改,则响应HTTP 304,告知浏览器继续使用所保存的cache。



    总结
    对于强制缓存,服务器通知浏览器一个缓存时间,在缓存时间内,下次请求,直接用缓存,不在时间内,执行比较缓存策略。
    对于比较缓存,将缓存信息中的Etag和Last-Modified通过请求发送给服务器,由服务器校验,返回304状态码时,浏览器直接使用缓存。

    下面图帮助理解执行过程

    缓存的不同来源

    from disk cache

    从磁盘中获取缓存资源,等待下次访问时不需要重新下载资源,而直接从磁盘中获取。它的直接操作对象为CurlCacheManager。

    from memory cache

    从内存中获取资源,等待下次访问时不需要重新下载资源,而直接从内存中获取。Webkit早已支持memoryCache。
    目前Webkit资源分成两类,一类是主资源,比如HTML页面,或者下载项,一类是派生资源,比如HTML页面中内嵌的图片或者脚本链接,分别对应代码中两个类:    MainResourceLoader和SubresourceLoader。虽然Webkit支持memoryCache,但是也只是针对派生资源,它对应的类为CachedResource,用于保存原始数据(比如CSS,JS等),以及解码过的图片数据。

    区别

    当退出进程时,内存中的数据会被清空,而磁盘的数据不会,所以,当下次再进入该进程时,该进程仍可以从diskCache中获得数据,而memoryCache则不行。

    相似

    diskCache与memoryCache相似之处就是也只能存储一些派生类资源文件。它的存储形式为一个index.dat文件,记录存储数据的url,然后再分别存储该url的response信息和content内容。Response信息最大作用就是用于判断服务器上该url的content内容是否被修改。

    用户行为

    最后附上一张,用户行为影响浏览器的缓存行为。


    实际场景应用缓存策略

    频繁变动的资源

    对于频繁变动的资源,首先需要使用 Cache-Control: no-cache 使浏览器每次都请求服务器,然后配合 ETag 或者 Last-Modified 来验证资源是否有效。这样的做法虽然不能节省请求数量,但是能显著减少响应数据大小。

    代码文件

    这里特指除了 HTML 外的代码文件,因为 HTML 文件一般不缓存或者缓存时间很短。
    一般来说,现在都会使用工具来打包代码,那么我们就可以对文件名进行哈希处理,只有当代码修改后才会生成新的文件名。基于此,我们就可以给代码文件设置缓存有效期一年 Cache-Control: max-age=31536000,这样只有当 HTML 文件中引入的文件名发生了改变才会去下载最新的代码文件,否则就一直使用缓存。

    参考文章:
    https://www.cnblogs.com/chenqf/p/6386163.html
    https://www.cnblogs.com/shixiaomiao1122/p/7591556.html
    以及yck掘金小册作者的浏览器缓存机制。
    特此感谢三篇文章作者。

    相关文章

      网友评论

        本文标题:HTTP缓存机制及原理

        本文链接:https://www.haomeiwen.com/subject/bagduqtx.html