web缓存

缓存是什么?

用户在浏览网站的时候,浏览器能够在本地保存网站中的图片或者其他文件的副本,这样用户再次访问该网站的时候,浏览器就不用再下载全部的文件,减少了下载量意味着提高了页面加载的速度。
如果中间加上一层CDN,那么用户浏览器与服务器的交互如下:
web缓存

客户端浏览器先检查是否有本地缓存是否过期,如果过期,则向CDN边缘节点发起请求,CDN边缘节点会检测用户请求数据的缓存是否过期,如果没有过期,则直接响应用户请求,此时一个完成http请求结束;如果数据已经过期,那么CDN还需要向源站发出回源请求(back to the source request),来拉取最新的数据。CDN的典型拓扑图如下:
web缓存

可以看到,在存在CDN的场景下,数据经历了客户端(浏览器)缓存和CDN边缘节点缓存两个阶段,下面分别对这两个阶段的缓存进行详细剖析。

insert缓存分类图:
web缓存

浏览器缓存

缓存行为主要由缓存策略决定,而缓存策略由内容拥有者设置。这些策略主要通过特定的HTTP头部来清晰地表达。

当一个用户发起一个静态资源请求的时候,浏览器会通过以下几步来获取资源(结合上图)

  • 本地缓存阶段: 先在本地查找该资源,如果有发现该资源,而且该资源还没有过期,就使用这一个资源,完全不会发送http请求到服务器;
    web缓存

  • 协商缓存阶段: 如果在本地缓存找到对应的资源,但是不知道该资源是否过期或者已经过期,则发一个http请求到服务器,然后服务器判断这个请求,如果请求的资源在服务器上没有改动过,则返回304,让浏览器使用本地找到的那个资源;
    web缓存

  • 缓存失败阶段: 当服务器发现请求的资源已经修改过,或者这是一个新的请求(在本来没有找到资源),服务器则返回该资源的数据,并且返回200, 当然这个是指找到资源的情况下,如果服务器上没有这个资源,则返回404。
    web缓存

用户操作行为与缓存

web缓存

浏览器中的操作对缓存的影响:

  • 强制刷新 – 当按下ctrl+F5来刷新页面的时候, 浏览器将绕过各种缓存(本地缓存和协商缓存), 直接让服务器返回最新的资源;
  • 普通刷新 – 当按下F5来刷新页面的时候,浏览器将绕过本地缓蹲来发送请求到服务器, 此时, 协商缓存是有效的
  • 回车或转向 – 当在地址栏上输入回车或者按下跳转按钮的时候, 所有缓存都生效

以下分别对各个阶段进行分析:

本地缓存阶段

  • Expires

指定缓存到期GMT的绝对时间,如果设了Cache-Control(下文)的max-age,max-age就会覆盖expires。如果expires到期需要重新请求。
web缓存

  • Cache-Control

    Cache-Control:这个是http 1.1中为了弥补 Expires 缺陷新加入的。

    浏览器总是优先使用cache-control,如果没有cache-control才考虑Expires.

    • max-age:(单位为s)指定设置缓存最大的有效时间,定义的是时间长短。当浏览器向服务器发送请求后,在max-age这段时间里浏览器就不会再向服务器发送请求了。

      Expires的方法很好,但是我们每次都得算一个精确的时间。max-age 标签可以让我们更加容易的处理过期时间。我们只需要说,这份资料你只能用一个星期就可以了。

      web缓存

    • s-maxage(单位为s)同max-age,只用于共享缓存(比如CDN缓存)

    • public: 表示缓存的版本可以被代理服务器或者其他中间服务器识别。

    • private: 意味着这个文件对不同的用户是不同的。只有用户自己的浏览器能够进行缓存,公共的代理服务器不允许缓存。

    • no-cache: 应理解为“不建议使用本地缓存”,其仍然会缓存数据到本地

    • no-store: 绝对禁止缓存,告诉浏览器在任何情况下都不要进行cache,不在本地保留拷贝。

    • must-revalidate、proxy-revalidate…不常用,这里不做过多解释

协商缓存阶段

  • Last-Modified & if-modified-since

    Last-Modified与If-Modified-Since是一对报文头,属于http 1.0。

    last-modified是web服务器认为对象的最后修改时间,比如文件的最后修改时间,动态页面的最后产生时间。

    再次访问时,浏览器会再次请求服务端,并携带上之前response的Last-Modified 指定的时间去服务器对比。对比成功返回304在本地加载数据,对比失败从服务器获取数据。

    web缓存

    • ETag & If-None-Match

    ETag与If-None-Match是一对报文,属于http 1.1。

    ETag是实体标签(Entity Tag)的缩写, 根据实体内容生成的一段hash字符串(类似于MD5或者SHA1之后的结果),可以标识资源的状态。 当资源发送改变时,ETag也随之发生变化。

    web缓存

    为什么使用ETag呢? 主要是为了解决Last-Modified 无法解决的一些问题。

    1. 某些服务器不能精确得到文件的最后修改时间, 这样就无法通过最后修改时间来判断文件是否更新了。
    2. 某些文件的修改非常频繁,在秒以下的时间内进行修改. Last-Modified只能精确到秒。
    3. 一些文件的最后修改时间改变了,但是内容并未改变。 我们不希望客户端认为这个文件修改了。

浏览器缓存刷新 (同用户操作行为与缓存)

1. 在地址栏中输入网址后按回车或点击转到按钮

浏览器以最少的请求来获取网页的数据,浏览器会对所有没有过期的内容直接使用本地缓存,从而减少了对浏览器的请求。所以,Expires,max-age标记只对这种方式有效。

2. 按F5或浏览器刷新按钮

浏览器会在请求中附加必要的缓存协商,但不允许浏览器直接使用本地缓存,它能够让 Last-Modified、ETag发挥效果,但是对Expires无效。

3. 按Ctrl+F5或按Ctrl并点击刷新按钮

这种方式就是强制刷新,总会发起一个全新的请求,不使用任何缓存。

CDN缓存

浏览器本地缓存失效后,浏览器会向CDN边缘节点发起请求。类似浏览器缓存,CDN边缘节点也存在着一套缓存机制。

CDN缓存的缺点

CDN的分流作用不仅减少了用户的访问延时,也减少的源站的负载。但其缺点也很明显:当网站更新时,如果CDN节点上数据没有及时更新,即便用户再浏览器使用Ctrl +F5的方式使浏览器端的缓存失效,也会因为CDN边缘节点没有同步最新数据而导致用户访问异常。

CDN缓存策略

CDN边缘节点缓存策略因服务商不同而不同,但一般都会遵循http标准协议,通过http响应头中的Cache-control: max-age的字段来设置CDN边缘节点数据缓存时间。

当客户端向CDN节点请求数据时,CDN节点会判断缓存数据是否过期,若缓存数据并没有过期,则直接将缓存数据返回给客户端;否则,CDN节点就会向源站发出回源请求,从源站拉取最新数据,更新本地缓存,并将最新数据返回给客户端。

CDN服务商一般会提供基于文件后缀、目录多个维度来指定CDN缓存时间,为用户提供更精细化的缓存管理。

CDN缓存时间会对“回源率”产生直接的影响。若CDN缓存时间较短,CDN边缘节点上的数据会经常失效,导致频繁回源,增加了源站的负载,同时也增大的访问延时;若CDN缓存时间太长,会带来数据更新时间慢的问题。开发者需要增对特定的业务,来做特定的数据缓存时间管理。

CDN缓存刷新

CDN边缘节点对开发者是透明的,相比于浏览器Ctrl+F5的强制刷新来使浏览器本地缓存失效,开发者可以通过CDN服务商提供的“刷新缓存”接口来达到清理CDN边缘节点缓存的目的。这样开发者在更新数据后,可以使用“刷新缓存”功能来强制CDN节点上的数据缓存过期,保证客户端在访问时,拉取到最新的数据。

H5缓存

还有一种我们都熟悉的缓存方式,LocalStorage和sessionStorage

LocalStorage是一种本地存储的公共资源,域名下很多应用共享这份资源会有风险;LocalStorage是以页面域名划分的,如果有多个等价域名之间的LocalStorage不互通,则会造成缓存多份浪费。

LocalStorage在PC上的兼容性不太好,而且当网络速度快、协商缓存响应快时使用localStorage的速度比不上304。并且不能缓存css文件。而移动端由于网速慢,使用localStorage要快于304。

在html中加载一个png图,首次加载的时候时间如下图:

web缓存

然而将图片使用了LocalStorage存储后,再次刷新后加载时间为0。

web缓存

而相对LocalStorage来说,SessionStorage的数据只存储到特定的会话中,不属于持久化的存储,所以关闭浏览器会清除数据。和localstorage具有相同的方法。

在前端开发中缓存是必不可少的,那么使用怎样的缓存方式更高效、让我们项目的性能更优,还是需要我们仔细斟酌。