通俗易懂的浏览器缓存讲解

写做背景

  • 在网络上,介绍信息类,传递资讯类的文章有不少,但真正让读者理解的文章却不多。
  • 笔者想作的,是结合本身的理解,将资讯以通俗易懂的方式表达出来。
  • 让读者不只仅了解该项技术,更理解其原理,清楚其流程,真正掌握它。
  • 笔者技术水平有限,文章可能有错误,遗漏的地方。敬请指导,期待与您的交流。

    Momo图

缓存状态码

200

  • 运行流程:【浏览器】--(200 form cache)--》【浏览器缓存】--》【页面展现】
  • 浏览器不须要向服务器发起请求,而是直接调用浏览器缓存的页面进行展现。

304

  • 运行流程:【浏览器】--》【服务器】--(304)--》【浏览器】--》【浏览器缓存】--》【页面展现】
  • 浏览器向服务器发起请求,并在请求头中携带该页面的特征值,如「最后修改时间」,「页面内容 hash 值」等。
  • 服务器接收到请求,对比请求头中携带的特征值,与服务器中页面的特征值是否一致。若是特征值没有变化,则认为该页面内容未发生变化,只返回 304 状态码的响应头,响应体为空。css

    • 通常而言,这部分逻辑,是不须要开发者手动实现的,是框架自带的。
    • 固然,开发者也能够经过某些设置关闭该功能,即直接返回服务器中的内容,无论与浏览器中缓存的是否是同样。
  • 浏览器接收到 304 响应头,调用浏览器缓存中的页面,进行内容展现。

什么状况下出现 304,何时出现 200 form cache ?

对于缓存过的页面,该页面的「URL的直接资源」会进行 304 处理,页面中须要加载的资源将进行 200 form cache 处理html

譬如

http://www.mongoosejs.net/docs/schematypes.html 这个页面。前端

  • http://www.mongoosejs.net/docs/schematypes.html 直接指向的 html, 即该页面的「URL的直接资源」,会进行 304 处理。
  • 除了接口之外,该 html 中须要加载的「其余资源」,如 css,js,图片等资源,都属于 200 form cache 资源。不管该资源是经过 html 中的标签载入,仍是经过 js 代码,动态载入。都属于「其余资源」。

为何这样设计呢?

  • 由于该页面的「URL的直接资源」,是该页面的首个资源,须要访问服务器肯定该页面是否有更新,须要给服务器更新资源的机会。若是个资源都不访问服务器,不与服务器沟通,那就没法得知服务器是否有资源更新。因此不管如何设置,调用页面的首个资源都是应当访问服务器的。
  • 而对于「其余资源」,不管「URL的直接资源」是否有变化,即便「URL的直接资源」 返回的不是 304,而是全新的内容,只要里面描述的「其余资源」对应 URL 没有变化。那浏览器在必定时间内(什么时间,后面会介绍到),都会直接调用缓存中的文件, 200 form cache。
  • 若是「URL的直接资源」(html)描述的「其余资源」(如,css,js)的 URL 发送了变化,浏览器就会当作新的资源文件,从服务器中从新获取(注意,是当作新资源获取,而不是判断是否更新的 304。由于是当作新的资源,而不是改变后的资源)。
  • 为何「其余资源」不像「URL的直接资源」那样,访问服务器判断更新?不访问怎么知道有没有更新呢?浏览器

    • 为何不访问服务器,由于这类资源的量通常比较多,即便内容没有发生变化,只返回 304,也须要通过 TCP 的三次握手和四次挥手。并且浏览器有同一域名的并发访问数量限制,都是须要消耗时间的。一旦资源大,这个时间成本就不可忽略了。因此不访问服务器,直接从浏览器缓存取。
    • 若是这些资源真的有变化怎么办?修改其对应的连接,把他当作新资源访问,经过修改「URL的直接资源」中的代码。哪怕是在后面加些参数,如加个时间串?v=20191120122038。浏览器也会当作新的资源。从服务器加载。
  • 因此即便你「其余资源」内容变化了,「URL的直接资源」没有改变(致使 html 中 css 的 URL 没有变化),对应的「其余资源」都直接调用缓存中的内容,不通过服务器,这也是前端同窗常常遇到的,没法显示最新效果的「缓存问题」。
  • 那是否是只有我不修改连接,就永远都不从新访问资源了呢?不是的,资源会有过时时间,若是超过了过时时间,就会从新访问服务器了。下一节会对其进行介绍。

各缓存头(请求头,响应头)

强缓存

服务端经过响应头告诉浏览器,「接下来的一段时间」内,直接使用缓存内容。缓存

  • 有没有以为很熟悉?没错,这就是应用在「其余资源」中的技术。为何访问「其余资源」时,不连接服务器,直接从浏览器缓存拿。由于这是服务器告诉浏览器的,也就是说,是服务端让浏览器从缓存中取的。不是浏览器自做主张设置的。
  • 那么「接下来的一段时间」是指那段时间呢?这是由服务器经过响应头告诉浏览器的。具体用到的响应头以下:
  • (http1.0)服务器

    • Expires:标识该资源过时的绝对时间,如Thu, 21 Nov 2019 00:10:44 GMT,这代表该资源于 2019年11月21日 00时11分44秒过时。在该时间点以前访问,则让浏览器直接从缓存上取。
  • (http1.1)网络

    • Cache-Control:接受多个参数,其中一个参数是定义过时时间。如Cache-Control: public, max-age=31536000,其中 max-age=31536000就是告知浏览器,在接收到该文件那一刻算起的 31536000 秒内有效,直接从浏览器缓存上取。

协商缓存

浏览器会向服务端发起http请求,而后服务端告诉浏览器文件未改变,让浏览器使用本地缓存。使用 Ctrl+F5强制刷新可使得缓存无效并发

  • 是的,这就是「URL的直接资源」应用的技术,协商缓存返回的就是 304 状态码。具体用到的响应头,请求头以下:
  • (http1.0)框架

    • Last-Modified/If-Modified-Since
    • 其中,在首次得到资源时,服务端携带的相应头是 Last-Modified,告诉浏览器该文件的最后修改时间。
    • 在浏览器再次发起请求时,就会将 Last-Modified 的值,携带到请求头中,并以 If-Modified-Since 为 key 保存。
    • 服务器在接收到 Last-Modified 请求头后,会与本地文件的修改时间进行比对,判断文件是否有变化,若是没有变化,则返回 304 状态码。
  • (http1.1)E-tag/If-None-Matchmongoose

    • 与 Last-Modified/If-Modified-Since 相似,只是判断的方式不一样,Last-Modified/If-Modified-Since 是用修改时间进行判断,If-None-Match/E-tag 则是经过文件内容的 hash 进行判断。此判断标准更加完全,准确。
    • 在首次得到资源时,服务端携带的响应头是 E-tag。告诉浏览器该文件内容的 hash 值。
    • 在浏览器再次发起请求时,将 E-tag 的值,携带到请求头中,并以 If-Modified-Since 为 key 保存。
    • 服务器在接收到 If-Modified-Since 请求头后,会与本地文件的 hash 值进行比对,判断文件是否有变化,若是没有变化,则返回 304 状态码。
  • 若是同时带有E-tag和Last-Modified,服务端会优先检查E-tag。

讲完了