美文网首页
轻松搞懂HTTP缓存,这一篇文章就够了

轻松搞懂HTTP缓存,这一篇文章就够了

作者: 辉夜真是太可爱啦 | 来源:发表于2021-12-16 11:02 被阅读0次

    大家好,我是辉夜真是太可爱啦 。故事的开始,要从一道经典的面试题开始说起, 从输入 URL 到页面加载完成,发生了什么? 相信大家应该对这个题目也很耳熟了。本系列是我 《一文搞懂JS系列》 之后的第二个系列。旨在让大家搞懂这个加载过程,从简答以及深入解答都能够对答如流

    前言

    大家好,我是辉夜真是太可爱啦

    在浏览器向服务器发起请求此之前,其实还有一步先查看是否有缓存。

    毕竟,网站上的有些资源其实早前可能已经获取过,既然本地直接有,为何还要大费周章地请求服务器再去拿一遍呢!

    所以,缓存的存在,自然有它的一定优势:

    • 减少了不必要的数据传输,节省带宽
    • 减少服务器的负担,提升网站性能
    • 加快了客户端加载网页的速度,提升用户体验

    先上思维导图:

    image.png

    那么,辉夜 就在想,我把网站上的所有东西,全部都缓存起来,那么,下次打开岂不是更快,顿时感觉自己是 性能优化大师

    事情哪有那么顺利 ,结果可想而知,当资源有更改的时候,如果客户端不及时更新会造成用户获取信息滞后,用户依旧使用的是缓存中的老版本,而且如果老版本有bug的话,情况那就只会更加糟糕。

    所以,彻底弄懂 HTTP 缓存,在工作中更合理地使用缓存,是十分重要的。

    那么首先,HTTP缓存其实分为两类,那就是 强缓存协商缓存

    强缓存

    强缓存的强,是 强制 的意思。听名字也知道,强缓存 的优先级在 协商缓存 的前面。

    它不需要发送请求到服务端,直接读取浏览器本地缓存,不得不说,确实挺 的。这下都直接把请求服务器的步骤都给去了,直接自给自足。

    然后,在强缓存中,又分为两种:

    image.png
    • from memory cache

      不访问服务器,直接读缓存,从内存中读取缓存。此时的数据时缓存到内存中的,当浏览器关闭后,数据将不存在。

    • from disk cache

      不访问服务器,直接读缓存,从磁盘中读取缓存,当浏览器关闭后,数据还是存在。

    强缓存主要由三个字段名来控制,Expires Cache-Control Pragma ,我们按照优先级从低到高依次介绍:

    (存储在硬盘或者是内存,并不是由这三个字段名来控制的,浏览器在获取资源之后(无论是强缓存或者协商缓存或者网络重新获取中取得的资源),就会将资源存储到内存中,下一次再获取的时候,就可以从内存中获取到了,当浏览器关闭之后,内存中的资源清空)

    Expires

    Expires 指的是过期时间,它的值是 GMT时间 。在浏览器发起请求时,会根据系统时间和 Expires 的值进行比较,如果系统时间超过了 Expires 的值,那么就代表缓存失效了。

    由于系统时间和服务器时间不一致的时候,就会存在校验不准确的情况,而且,系统时间是可以用户自行设定的。所以,它的优先级自然是最低的。

    Cache-Control

    顾名思义,缓存控制。它是一个对象,比较常用的属性值有:

    • max-age

      直白翻译就是最大年龄,单位是秒。缓存时间计算的方式是距离发起的时间的秒数,超过间隔的秒数缓存失效。

      这里可以将长时间内稳定不变的资源设为很大的值,例如网站的 Logo 等文件。

    • no-cache

      不使用强缓存,需要与服务器验证缓存是否新鲜(即使用协商缓存)。

      这种方法就是它每次都会去服务器做一次验证,验证当前是否是最新的资源,如果过期了,则从服务器再重新获取一份。可以对那些经常需要更新的资源文件采用这种方式。

    • no-store

      禁止使用缓存(包括协商缓存),每次都向服务器请求最新的资源。

      这种方法能保证每次获取到最新的资源,但是缺点也很明显,就是它每次都会重新去服务器拉去一下资源文件。可以对那些必须是最新资源的文件(实时性极高的文件)采用这种方式。

    • private

      专用于个人的缓存,中间代理、CDN 等不能缓存此响应。

    • public

      响应可以被中间代理、CDN 等缓存

    • must-revalidate

      在缓存过期前可以使用,过期后必须向服务器验证

    Pragma

    Pragma 只有一个属性值,就是 no-cache ,效果和 Cache-Control 中的 no-cache 一致,不使用强缓存,需要与服务器验证缓存是否新鲜,在 3 个头部属性中的优先级最高。

    协商缓存

    当设置了不走强缓存,或者是强缓存过期失效的时候,就会走协商缓存。

    协商缓存,就是客户端和服务器之间互相协商的结果。

    • Last-Modified / If-Modified-Since

      二者的值都是 GMT 格式的时间字符串。

      1. 浏览器第一次向服务器发起请求,服务器的 Respone Header 中加上 Last-Modified 标记,表示此资源的最后修改时间。

      2. 浏览器再次跟服务器请求这个资源时,在 Request Header上加上 If-Modified-Since 标记,这个Header 的值就是上一次请求时返回的 Last-Modified 的值

      3. 服务器接收到资源请求之后,将接收到的 If-Modified-Since 和现在资源的最后修改时间进行对比。

        如果无变化,则返回 304 Not Modified ,但是不会返回资源信息

        如果有变化,则返回新的资源内容,以及新的 Last-Modified 标记。

      4. 浏览器收到 304 的响应后,就会从缓存中加载资源

      5. 如果没有命中缓存,浏览器直接从服务器加载资源时,Last-Modified 的 Header 在重新加载的时候会被更新,下次请求时,If-Modified-Since 会启用上次返回的 Last-Modified

      这种方式看似完美无瑕,但是,也有它的一定缺陷:

      ① 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;

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

      ③ 某些服务器不能精确的得到文件的最后修改时间。

      所以,为了解决上述中可能会出现的问题,后面就有了 ETag / If-None-Match 的出现。

      ETag / If-None-MatchLast-Modified / If-Modified-Since 可以同时出现,但是 ETag / If-None-Match优先级更高

    • ETag / If-None-Match

    ETag 是服务器自动生成或者由开发者生成的对应资源在服务器端的 唯一hash标识符 ,例如 67690D623E0034098C6998E9233565A7

    当服务端的文件变化的时候,它的 hash码会随之改变。其判断过程与 Last-Modified/If-Modified-Since 类似。

    ETag 又有强弱校验之分,如果 hash 码是以 W/ 开头的一串字符串,例如 W/"5eb03d6a-36a9" ,说明此时协商缓存的校验是弱校验的,只有服务器上的文件差异(根据 ETag 计算方式来决定)达到能够触发 hash 值后缀变化的时候,才会真正地请求资源,否则返回 304 并加载浏览器缓存。

    整体流程图

    image.png

    参考资料

    图解 HTTP 缓存

    http协商缓存VS强缓存

    相关文章

      网友评论

          本文标题:轻松搞懂HTTP缓存,这一篇文章就够了

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