浏览器缓存机制介绍之http缓存-强缓存-协商缓存

前言

缓存的基本策略是拿空间换时间.意思就是我们将数据存储起来,牺牲空间,在下次使用的时候直接拿存储的,减少请求时间.

浏览器缓存机制有四个方面,它们按照获取资源时请求的优先级依次排列如下:

memory cache>service worker cache>http cache>push cache

为了防止篇幅过长,影响阅读体验,我对每一种缓存都会单独写一篇文章,本文主要是讲我们最常用的http缓存.

缓存是服务器端来设置的,前端无法设置!

http缓存

页面通过http获取资源,如果每次资源都通过http去获取,无疑是很消耗性能的,用户的体验并不好.所以我们在完成一次http通讯后,可以将部分资源缓存起来,等到再次使用的时候,直接从缓存中拿,不需要在从服务器中获取了,大大提高了性能.

http缓存有2种:强缓存和协商缓存

强缓存

请求发出时,浏览器回去判断是否命中Expires和Cache-Control两个字段中设置的强缓存,如果命中,那么会直接从缓存中拿取资源,不会与服务器发生通信

Expires

express是http1.0中关于强缓存的设置项,值是缓存过期时间.如下图是在network中截取的强缓存样子.

在第一次请求完毕后,当再次请求时,浏览器就会先对比本地时间和 expires 的时间戳,如果本地时间小于 expires 设定的过期时间,那么就直接去缓存中取这个资源。

expires设置强缓存对本地时间的依赖导致缓存在某些情况下会出现bug

cache-control

cache-control是http1.1中关于缓存的设置项,值有no-cache、no-store、public、private、max-age

相比于expires,cache-control可以用max-age更精准的设置强缓存的过期时间,因为max-age的值是秒,表示在上一次请求后的多少秒内,强制缓存生效.解决了expires时间戳带来的bug

cache-control可以看作是expires的完全替代方案,在请求中国呢expires存在的唯一作用就是为了兼容http1.0.

cache-control的优先级也比expires高,当同时存在时,我们以cache-control为标准

Response Headers中max-age的样式

cache-control: max-age=360000

cache-control其他设置项的功能:

no-cache:绕开浏览器换取,请求去询问服务器缓存是否更新,走协商缓存的路线

no-store:绕开浏览器缓存和服务器缓存,每次请求都会重新下载完整的资源

public:资源可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器

private:资源只能被当前客户端缓存,不能被代理服务器缓存 

private是我们默认的设置,但是通常如果我们设置了max-age就会自动开启public模式

协商缓存

协商缓存是每次请求时,都回去服务器询问资源是否更新,如果资源没有更新,会返回304状态码让浏览器读取本地缓存;如果服务器资源更新了就会返回更新后的资源

判断再次请求时服务端资源是否更新是协商缓存的重点,这涉及到几个字段:Etag搭配If-None-Match、Last-Modified搭配If-Modified-Since

Last-Modified搭配If-Modified-Since

last-modified值是第一次请求发生时的时间戳,它会随着响应头返回,再次请求的时候请求头会携带上If-Modified-Since,该字段的值是上一次请求的last-modified的值.目的是让服务器知道上一次请求的时间,对比该资源在服务器上最后一次修改的时间,判断在这段时间内资源是否发生了改变

Last-Modified: Fri, 27 Oct 2017 06:35:57 GMT
If-Modified-Since: Fri, 27 Oct 2017 06:35:57 GMT

使用last-modified有一些缺点:

  • 我们编辑了文件,但文件的内容没有改变。服务端并不清楚我们是否真正改变了文件,它仍然通过最后编辑时间进行判断。因此这个资源在再次被请求时,会被当做新资源,进而引发一次完整的响应——不该重新请求的时候,也会重新请求。

  • 当我们修改文件的速度过快时(比如花了 100ms 完成了改动),由于 If-Modified-Since 只能检查到以秒为最小计量单位的时间差,所以它是感知不到这个改动的——该重新请求的时候,反而没有重新请求了。

为了解决这些缺点etag应运而生.

 Etag搭配If-None-Match

etag的算法和资源内容有关.服务端会根据资源的内容生成一个唯一的etage.当我们修改资源时,资源内容改变会重新生成etag.

当我们请求一次资源后,浏览器会通过响应头返回一个etag值.再次请求资源时,http的请求头会携带一个if-None-Match字段,该字段的值就是etag的值.目的是为了给服务器做对比

 为什么要有etag?

  • 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;
  • 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);

 总结

以上就是http缓存的全部内容了,使用强缓存还是协商缓存依据情况而定.

原文地址:https://www.cnblogs.com/liuXiaoDi/p/13052696.html