浏览器的缓存

408 阅读14分钟

实例场景:访问页面时使用页面的“返回”功能,会发现网页加载非常快;直接输入之前访问过的URL,浏览器会快速加载页面等。

什么是缓存:第一次访问网站时,计算机会将网站上的图片和数据下载到本地,当再次访问的时候,网站就会直接从本地存储中直接加载出来。

浏览器缓存的优点:存储一些简单的、使用频率高的数据,可避免多次访问服务器同时节省网络资源等。 Wed缓存种类:数据库缓存,CDN缓存,代理服务器缓存,浏览器缓存 img 所谓的浏览器缓存就是在本地计算机中开辟一块内存区与硬盘区,硬盘区用于数据传输缓冲,暂存用户的历史访问数据。

浏览器的缓存过程

1.强缓存

不会向服务器发送请求,直接从缓存读取资源,返回200状态码,在 Chrome 中,强缓存又分为 Disk Cache (存放在硬盘中)和 Memory Cache (存放在内存中),存放的位置是由浏览器控制的。是否强缓存由 Expires、Cache-Control 和 Pragma 3 个 Header 属性共同来控制。

原理:

①第一次加载,页面会向服务器请求数据,并在 Response Header 中添加 Cache-Control, expires,pragma参数,通过接口返回浏览器。浏览器根据请求头(Response Header)里面是否存在expires,pragma,cache-control等字段判断是否为强制缓存,若存在,浏览器将资源数据存储到memory cache或者disk cache中。一般情况,存存储图像和网页等资源主要缓存在disk cache,操作系统缓存文件等资源大部分都会缓存在memory cache中。

②再次请求时,浏览器判断请求头中的cache-control参数,对比时间参数是否过期,如果没有,返回http状态码200 (注:在Chrome 中会指明200 from memory cache还是200 from disk cache),从本地缓存拿数据。否则将缓存标识写入response header中,判断是否符合协商缓存,符合就返回http状态码304 ,然后从缓存拿数据。否则向服务器发送请求获取新的数据。 img 强缓存主要分三种情况:

  1. 不存在该缓存结果和缓存标识,强制缓存失效,则直接向服务器发起请求(跟第一次发起请求一致) 图片 1.存在该缓存结果和缓存标识,但该结果已失效,强制缓存失效,则使用协商缓 图片 2.存在该缓存结果和缓存标识,且该结果尚未失效,强制缓存生效,直接返回该结果 图片 expires

是HTTP1.0控制网页缓存的字段,值为一个时间戳,准确来讲是格林尼治时间,服务器返回该请求结果缓存的到期时间,意思是,再次发送请求时,如果未超过过期时间,直接使用该缓存,如果过期了则重新请求。

有个缺点,就是它判断是否过期是用本地时间来判断的,本地时间是可以自己修改的,就可能会与服务器的时间不一致。

Cache-Control

HTTP1.1中启用Cache-Control 来控制页面的缓存与否,Cache-Control属性是在服务器端配置的,不同的服务器有不同的配置,使用的是相对时间概念。

Cache-Control的属性设置:

  • (1). max-age:设置缓存的最大的有效时间,单位为秒(s),这是一个时间段。max-age会覆盖掉Expires
  • (2). s-maxage:只用于共享缓存,比如CDN缓存(s -> share)。与max-age 的区别是:max-age用于普通缓存, 而s-maxage用于代理缓存。如果存在s-maxage,则会覆盖max-age 和 Expires
  • (3). public:响应会被缓存,并且在多用户间共享。默认是public
  • (4). private:响应只作为私有的缓存,不能在用户间共享。如果要求HTTP认证,响应会自动设置为private
  • (5). no-cache:指定不缓存响应,表明资源不进行缓存。但是设置了no-cache之后并不代表浏览器不缓存,而是在缓存前要向服务器确认资源是否被更改(即协商缓存)
  • (6). no-store:绝对禁止缓存
  • (7). must-revalidate:如果页面过期,则去服务器进行获取

目前Cache-Control请求字段被各个浏览器支持的较好,其优先级也比较高,当和别的字段(如Expires)一起用时,会覆盖其他字段。 img pragma

这个是HTTP1.0中禁用网页缓存的字段,其取值为no-cache,和Cache-Control的no-cache效果一样。 img 浏览器缓存位置:Service Worker-->Memory Cache-->Disk Cache-->Push Cache。

1.Service Worker

是运行在浏览器背后的独立线程,一般可以用来实现缓存功能。使用 Service Worker的话,传输协议必须为 HTTPS。因为 Service Worker 中涉及到请求拦截,所以必须使用 HTTPS 协议来保障安全。Service Worker 的缓存与浏览器其他内建的缓存机制不同,它可以让我们自由控制缓存哪些文件、如何匹配缓存、如何读取缓存,并且缓存是持续性的。

2. Memory Cache

内存中的缓存,主要包含的是当前中页面中已经抓取到的资源,例如页面上已经下载的样式、脚本(如JavaScript代码)、图片等。读取内存中的数据肯定比磁盘快,内存缓存虽然读取高效,可是缓存持续性很短,会随着进程的释放而释放。一旦我们关闭 Tab 页面,内存中的缓存也就被释放了。

(因为CSS文件加载一次就可渲染出来,我们不会频繁读取它,所以它不适合缓存到内存中,但是js之类的脚本却随时可能会执行,如果脚本在磁盘当中,我们在执行脚本的时候需要从磁盘取到内存中来,这样IO开销就很大了,有可能导致浏览器失去响应。)

3. Disk Cache

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

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

memory cache 要比 disk cache 快的多。举个例子:从远程 web 服务器直接提取访问文件可能需要500毫秒(半秒),那么磁盘访问可能需要10-20毫秒,而内存访问只需要100纳秒,更高级的还有 L1缓存访问(最快和最小的 CPU 缓存)只需要0.5纳秒。

img prefetch cache(预取缓存)

link标签上带了prefetch,再次加载会出现。

prefetch是预加载的一种方式,被标记为prefetch的资源,将会被浏览器在空闲时间加载。

4. Push Cache

Push Cache(推送缓存)是 HTTP/2 中的内容,当以上三种缓存都没有命中时,它才会被使用。它只在会话(Session)中存在,一旦会话结束就被释放,并且缓存时间也很短暂,在Chrome浏览器中只有5分钟左右,同时它也并非严格执行HTTP头中的缓存指令。

2.协商缓存

强缓存失效后,浏览器在请求头中携带相应的的缓存tag向服务器发请求,服务器根据这个tag来判断是否命中协商缓存。具体上tag分为Last-Modified和ETag.

  • 协商失效:服务器返回304,浏览器在缓存中找资源 img 失败:服务器返回200和请求数据,浏览器将数据缓存 img 设置协商缓存:

Last-Modified / If-Modified-Since img 流程:

  1. 浏览器第一次给服务器发送请求的时候,服务器就会在在response header中添加请求资源的上次更新时间,就是last-modified,浏览器会缓存下这个时间。
  2. 然后浏览器再次发送请求时,request header中带上if-modified-since:[保存的last-modified的值]。根据浏览器发送的修改时间和服务端的修改时间进行比对,一致的话代表资源没有改变,服务端返回正文为空的响应,让浏览器中缓存中读取资源。若服务器的资源最后被修改时间大于If-Modified-Since的字段值,则重新返回资源,状态码为200;否则则返回304,代表资源无更新,可继续使用缓存文件。 img Etag / If-None-Match

流程:

  1. 浏览器第一次给服务器发送请求的时候,服务器会在其头部添加etag的值,然后再下一次请求在request header中带上if-none-match:[保存的etag的值]。
  2. 通过发送的etag的值和服务端重新生成的etag的值进行比对,(每发一次服务器都会生成一个etag值与请求头部的etag做对比)如果一致代表资源没有改变,服务端返回正文为空的响应,告诉浏览器从缓存中读取资源。一致则返回304,代表资源无更新,继续使用缓存文件;不一致则重新返回资源文件,状态码为200。

etag能够解决last-modified的一些缺点,但是etag每次服务端生成都需要进行读写操作,而last-modified只需要读取操作,性能开销更大。

两者对比

  1. 精准度上,ETag优于Last-Modified。优于 ETag 是按照内容给资源上标识,因此能准确感知资源的变化。而 Last-Modified 就不一样了,它在一些特殊的情况并不能准确感知资源变化,主要有两种情况:
  • 编辑了资源文件,但是文件内容并没有更改,这样也会造成缓存失效。
  • Last-Modified 能够感知的单位时间是秒,如果文件在 1 秒内改变了多次,那么这时候的 Last-Modified 并没有体现出修改了。
  1. 在性能上,Last-Modified优于ETag,也很简单理解,Last-Modified仅仅只是记录一个时间点,而 Etag需要根据文件的具体内容生成哈希值。

另外,如果两种方式都支持的话,服务器会优先考虑ETag

缓存方案

目前市场主要的缓存设置方案是:

  • HTML:协商缓存
  • CSS,JS,图片:强缓存,文件名带上hash。

缓存区别

  • 强缓存不发请求到服务器,浏览器对资源更新情况不能实时了解;协商缓存发送请求到服务器,资源的更新,浏览器知道。
  • 大部分Wed服务器默认开启协商缓存。

刷新的影响

  1. 当ctrl+f5强制刷新网页时,直接从服务器加载,跳过强缓存和协商缓存。
  2. 当f5刷新网页时,跳过强缓存,但是会检查协商缓存。
  3. 浏览器地址栏中写入URL,回车 浏览器发现缓存中有这个文件了,不用继续请求了,直接去缓存拿。(最快)

浏览器的存储

浏览器的存储是相对于外存,一般是指在计算机本地的浏览器存储空间。

image.png

Cookie

cookie 的设置过程
  1. 客户端向服务器发送一个 HTTP 请求。
  2. 服务器接收到请求后在响应头添加一个 set-cookie 的字段
  3. 客户端接收到服务器的响应后将 cookie 保存下来,保存到本地的文件夹内
  4. 之后浏览器每一次请求都会携带 cookie 发送给服务器(耗性能)
  • Cookie 的某一些属性

    • Name:就是 cookie 的属性名
    • Value:cookie 的属性值,需要做编码处理
    • Expire:设置 cookie 的过期时间,Set-Cookie:Expires=Wed, 21 Oct 2015 07:28:00 GMT; 需要注意的是如果 cookie 的 Expire 没有设置,那么表示这个 cookie 是会话 cookie 浏览器关闭后就消失了。持久性的 cookie 是存放在硬盘中的,直到时间过期或者手动清除
    • max-age:表示 cookie 失效之前的秒数,Set-Cookie:Max-Age=604800; 这个属性的值可以是正数:表示持久性的 cookie。负数:表示会话的 cookie 浏览器关闭就消失。0:表示立即删除这个cookie。当 Max-Age 和 Expire 都存在是,Max-Age 的优先级更高
    • size:cookie 的大小,超过 4kB 后会被忽略。
    • Domain: 记录域名信息, 但是不能跨站点设置域名,不会起作用
    • path:Path属性指定浏览器发出 HTTP 请求时,哪些路径要附带这个 Cookie。
    • SameSite:限制第三方对 cookie 的携带请求,这属性可以防止 CSRF 攻击。三个重要的属性 strict: 禁止第三方请求携带 cookie。Lax:允许部分第三方携带 cookie 值。None 无论是否跨站都会发送 Cookie。一开始默认值是 None,后来默认值是 Lax。
    • HttpOnly: 限定 cookie 只能通过 HTTP 传输,JavaScript 不能读取,防止 XSS 攻击
    • Secure:限定了只有 HTTPS 才可以传输 cookie
Cookie的缺陷:
  • 只要匹配到同域名下的请求且路径正确,无论是否需要Cookie都会随着每一个请求一起发送,随着请求数量增加,也导致了其降低网络性能的缺陷。
  • Cookie不够大,4KB的上限让其只能存储一些简单、少量的数据。此外,很多浏览器对Cookie的个数也有不同的限制
  • 在Http请求中Cookie是明文传送的,安全问题堪忧。

Wed Storage

localStorage

localStorage 存值的方式和 cookie 类似,都会存放在同一个域名下,localStorage 可以长期存储,没有时间的限制。

localStorage 优点

1.扩展了 cookie 的存储大小,可以存放 5M 大小,不同浏览器不同;

2.只存储在浏览器不会和服务器之间有通信解决了cookie 的安全问题和性能消耗问题。

localStorage 缺点

1.需要手动删除保存的数据;

2.只支持字符串类型,JSON 类型需要通过JSON.stringify() 转化。

localStorage 使用场景:利用 localStorage 可以存放一些稳定的资源和base64的图片等

sessionStorage

sessionStorage与localStorage基本一致,不同在于其是会话级别的存储,浏览器页面关闭sessionStorage会清零。

indexedDB

浏览器提供的非关系型数据库,indexedDB 提供大量的接口提供查询功能,还能建立查询。可以把 IndexedDB 看做是 Local Storage 的升级版,当数据复杂度和规模上升到 Local Storage 无法处理的地步时就可以考虑使用 IndexedDB。

  • 以键值对(key-value)的形式存储值,包括 js 对象
  • indexedDB 是异步的,存入数据不会导致页面卡顿。
  • indexedDB 支持事务,事务是一系列操作过程中发生了错误,数据库会回退到操作事务之前的状态。
  • 同源限制,不同源的数据库不能访问。
  • 存储空间没有限制。
  • 支持二进制储存。

Web SQL

Web SQL 数据库 API 实际上不是 HTML5 规范的一部分,而是一个单独的规范,它引入了一组 API 来使用 SQL 来操作客户端数据库。需要注意的是,HTML5 已经放弃 Web SQL 数据库。

Web SQL Database 规范中定义的三个核心方法:

  • openDatabase:这个方法使用现有数据库或新建数据库来创建数据库对象;
  • transaction:这个方法允许我们根据情况控制事务的提交或回滚;
  • executeSql:这个方法用于执行真实的 SQL 语句。

Web SQL 的特点(相比 Cookie、localStorage 与 sessionStorage):

  • Web SQL 能方便进行对象存储;
  • Web SQL 支持事务,能方便地进行数据查询和数据处理操作。