Http缓存机制整理

728 阅读4分钟

HTTP缓存:用于临时存储(缓存)Web文档(如HTML页面、js及图像),以减少服务器延迟的一种信息技术。

HTTP缓存系统会将通过该系统的文档副本保存下来,如果满足某些条件,则可以通过缓存内容来返回请求结果。HTTP缓存系统可以是设备,也可以是计算机程序。

使用缓存是提高网页打开速度的一种方式,也几乎是我们性能优化的首选方案。优秀的缓存策略可以缩短网页请求资源的距离、减少延迟,并且由于缓存文件可以重复利用,因此可以减少宽带、降低网络负荷

很多时候,大家倾向于将浏览器缓存简单地理解为“HTTP缓存”。但事实上,HTTP缓存属于浏览器缓存的一种。

浏览器的资源缓存又可以分为两大类:内存缓存和磁盘缓存

当首次访问网页时,资源文件被缓存在内存中,同时也会在本地磁盘中保留一份副本。

当用户刷新页面时候,如果缓存的资源没有过期,就可以直接在内存中读取数据并加载,当用户关闭页面后,当前页面缓存在内存中资源就会被清空。所以内存中缓存最先被浏览器尝试去命中,从效率上说,是响应最快的一种缓存,但也是“短命”的,页面关闭后就被清空。

当用户再次访问页面时,如果资源文件的缓存没有过期,就可以从本地磁盘加载数据并再次缓存到内存中。 

下面是几种典型的刷新操作对应的缓存行为转换表格:

HTTP缓存详解

强缓存

强缓存是利用http头中的Expires和Cache-Control两个字段来控制的。若命中则直接从缓存中获取资源,不会再与服务端发生通信。返回的HTTP状态码为200。如下图

expires:是通过绝对的时间戳来控制缓存过期的时间。

max-age:是通过相对的时间长度来达到同样的目的。max-age可以是对expires能力的补位/替换。当下的前端实践中,我们普遍会倾向于使用max-age。max-age相对于expires的优先级更高,当Cache-Control与expires同时出现时,以cache-control为准。

no-cache:绕开了浏览器,每一次发起请求就直接向服务端去确认该资源是否过期(过期就向服务器发起请求,不过期就进行协商缓存)。

no-store:不使用任何缓存策略,直接向服务器发起请求。

public:如果资源设置了public,那么它既可以被浏览器缓存,也可以被代理服务器缓存;

private:资源只能被浏览器缓存。private也是默认值。

协商缓存

协商缓存机制下,浏览器需要向服务器去询问缓存的相关信息,进而判断是重新发起请求,还是从本地获取缓存资源。

如果服务端提示缓存资源未改变(Not Modified),资源会被重定向到浏览器缓存,对应的状态码是304,如下图:

**Last-modified:**是一个时间戳,在启用了协商缓存后,会在首次启用时,返回Last-modified,随后每次请求时,都会带上上次返回的Last-modified值作为If-Modified-Since的值,服务器接收到这个时间戳后,会比对该时间戳与服务器上最后修改资源的时间是否一致,若变化,就返回新的Last-Modified值,否则就返回304,Response Headers也不会再添加Last-modified字段。

Last-Modified存在常见的两个弊端:

1,编辑了文件,但文件内容没变,服务端仍然会通过编辑时间进行判断。原本不需要进行重新请求,也会重新请求。

2,修改文件内容的速度过快,由于Last-modified-Since只能检查到以秒为单位的时间差,无法感知毫秒内的变化。原本该重新请求,确没有重新请求。

Etag:由服务器为每个资源生成的唯一标识字符串,Etag是基于文件内容编码的,只要文件内容不同,它们对应的Etag就不同。

Etag也是在首次请求时,Response Headers会在响应头里获取一个最初的标识符字符串。那么在下次请求时,会把请求头里面的Etag作为if-None-Match的值提供给服务端比对,与Last-modified类似。弊端就是需要服务器额外的开销,会影响服务端的性能。

注意Etag不能替代Last-Modified,只能作为Last-modified的强化与补充而存在。Etag在感知文件变化上比Last-modified更加准确,优先级也更高;当Last-Modified和Etag同时存在,则以Etag为准。