浏览器中的缓存方式

本文最后更新于:9 个月前

浏览器缓存(http缓存)

  先看看浏览器发起请求和,内部是个什么流程:

  如图,浏览器会先问自己有没有缓存,缓存是否过期了,然后去问服务器关于资源的问题。如此我们先解决第一个问题,浏览器自己的缓存是放在什么地方了。

  从浏览器的network里可以看到资源会放在memory cachedisk cache里。

memory cache 和 disk cache

memory cache

顾名思义,就是将资源缓存到内存中,等待下次访问时不需要重新下载资源,而直接从内存中获取。Webkit早已支持memoryCache。目前Webkit资源分成两类

  • 一类是主资源,比如HTML页面,或者下载项
  • 一类是派生资源,比如HTML页面中内嵌的图片或者脚本链接

分别对应代码中两个类:MainResourceLoaderSubresourceLoader。虽然Webkit支持memoryCache,但是也只是针对派生资源,它对应的类为CachedResource,用于保存原始数据(比如CSS,JS等),以及解码过的图片数据。

diskCache

顾名思义,就是将资源缓存到磁盘中,等待下次访问时不需要重新下载资源,而直接从磁盘中获取,它的直接操作对象为CurlCacheManager。它与memoryCache最大的区别在于,当退出进程时,内存中的数据会被清空,而磁盘的数据不会,所以,当下次再进入该进程时,该进程仍可以从diskCache中获得数据,而memoryCache则不行。diskCachememoryCache相似之处就是也只能存储一些派生类资源文件。它的存储形式为一个index.dat文件,记录存储数据的url,然后再分别存储该urlresponse信息和content内容。Response信息最大作用就是利用Last-Modified等标记来判断服务器上该urlcontent内容是否被修改。

读取缓存的优先级

  1. 先看内存有没有,有就直接加载
  2. 没有就在看磁盘有没有,有就直接加载
  3. 还没有就只能访问网络请求拿数据
  4. 拿到后存到对应的地方

浏览器缓存分类

强缓存

  强缓存就是向浏览器缓存查找该请求结果,并根据该结果的缓存规则来决定是否使用该缓存结果的过程。
缓存是否存在取决的我们是否缓存了和是否有效期过了,这里就涉及到两个头字段的属性了。

  • Expires

该字段是 http1.0 时的规范,它的值为一个绝对时间的GMT格式的时间字符串,比如Expires:Mon, 30 Nov 2020 02:23:37 GMT。这个时间代表着这个资源的失效时间,在此时间之前,就可以命中缓存。但是这种方式有较大的问题,因为是利用时间戳进行判断的,一旦系统的时间有问题,就会出现缓存混乱的问

  • Cache-Control

Cache-Controlhttp1.1时出现的header信息,主要是利用该字段的 max-age值来进行判断,它是一个相对时间,例如Cache-Control:max-age=3600,代表着资源的有效期是3600秒。

  此外,cache-control除了max-age字段外,还有下面几个比较常用的设置值:

  • no-cache:需要进行协商缓存,发送请求到服务器确认是否使用缓存。
  • no-store:禁止使用缓存,每一次都要重新请求数据。
  • public:可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器。
  • private:只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存。

  Cache-ControlExpires可以在服务端配置同时启用,同时启用的时候 Cache-Control 优先级高

协商缓存

  协商缓存浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程。
  其中header中的缓存标识有:if-Modified/if-Modified-SinceEtag/if-none-match,其中Etag/if-none-match会先被服务器验证,之后再去查验if-Modified的情况

  • if-Mif-Modifiedif-Modified/if-Modified-Since
    第一次请求一个资源的时候,服务器会在头部加上if-Modified字段来告诉浏览器最后一次修改的时间什么时候。然后浏览器再次请求相同资源时,会附加if-Modified-Since字段,该字段为之前if-Modified的值,服务器据此判断资源是否被修改过,如果没变化,就返回304,告诉浏览器用之前的资源就好了,这资源咱就不再重复传了。
  • Etag/if-none-match
    和上面情况相同,不过返回的值是一个Etag校验码,用来标识资源是否有变动,不过在确认没变化后除了返回304,还有传回一个Etag

PS:我个人认为当某些资源可能是长时间都不会有变动的时候,我们对他使用强缓存设置一个较长的过期时间,然后此类资源就可以在我们可控的范围内免去网络请求而直接在本地获取。如果某些资源变动的较为频繁,我们会去使用协商缓存来保证当服务器资源被修改后能立刻获取新资源,如果没有资源变动那么也可以省去重新下载的步骤。

本地缓存

  Cookie 是直接存储在浏览器中的一小串数据。它们是 HTTP 协议的一部分,由 RFC 6265 规范定义。
  Cookie 通常是由 Web 服务器使用响应 Set-Cookie HTTP-header 设置的。然后浏览器使用 Cookie HTTP-header 将它们自动添加到(几乎)每个对相同域的请求中。
  最常使用的就是登录验证,整个过程中,客户端登录后,服务器在响应中使用 Set-Cookie HTTP-header 来设置具有唯一“会话标识符(session identifier)cookie。下次如果请求是由相同域发起的,浏览器会使用Cookie HTTP-header通过网络发送 cookie。所以服务器就知道是谁发起了请求。

sessionStorage

  sessionStorage属性允许你访问一个,对应当前源的session Storage对象。它与localStorage相似,不同之处在于localStorage里面存储的数据没有过期时间设置,而存储在 sessionStorage 里面的数据在页面会话结束时会被清除。

  • 页面会话在浏览器打开期间一直保持,并且重新加载或恢复页面仍会保持原来的页面会话

  • 在新标签或窗口打开一个页面时会复制顶级浏览会话的上下文作为新会话的上下文,这点和 session cookies 的运行方式不同

  • 打开多个相同的URL的Tabs页面,会创建各自的sessionStorage。

  • 关闭对应浏览器窗口(Window)/ tab,会清除对应的sessionStorage。

    LocalStorage

      localStorage 最主要的特点是:

  • 在同源的所有标签页和窗口之间共享数据。

  • 数据不会过期。它在浏览器重启甚至系统重启后仍然存在。

  只读的localStorage属性允许你访问一个Document源(origin)的对象 Storage;存储的数据将保存在浏览器会话中。localStorage 类似 sessionStorage,但其区别在于:存储在 localStorage 的数据可以长期保留;而当页面被关闭时,存储在 sessionStorage 的数据会被清除。
  无论数据存储在 localStorage 还是 sessionStorage ,它们都特定于页面的协议。另外,localStorage 中的键值对总是以字符串的形式存储。 (需要注意, 和js对象相比, 键值对总是以字符串的形式存储意味着数值类型会自动转化为字符串类型).

IndexedDB

  IndexedDB 是一个用于在浏览器中储存较大数据结构的 Web API, 并提供索引功能以实现高性能查找. 像其他基于 SQL 的 关系型数据库管理系统 (RDBMS) 一样, IndexedDB 是一个事务型的数据库系统. 然而, 它是使用 JavaScript 对象而非列数固定的表格来储存数据的.它比 localStorage 强大得
多。

  • 通过键和多种键的类型来存储几乎任何类型的值。
  • 支撑事务的可靠性
  • 支持键范围查询、索引
  • 和 localStorage 相比,它可以存储更大的数据量。

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!