强缓存和协商缓存

之前一直对浏览器缓存只能描述一个大概,深层次的原理不能描述上来;为了泄恨,查阅一些资料最终对其有了一个更深入的理解

本文主要讲解浏览器端的缓存,缓存的作用是不言而喻的,能够极大的改善网页性能,提高用户体验。

浏览器缓存的基本认识

分为强缓存协商缓存

(1)浏览器在加载资源的时候,会根据HTTP的头部header判断它是否命中强缓存,强缓存如果直接命中,那么浏览器就会直接从自己的缓存中读取资源,而不会请求到服务器。比如某个css文件,如果浏览器在加载这个文件的时候,从这个文件的http头部判断命中了缓存,那么就会直接从内存中读取这个css文件,而不会再去请求服务器。

(2)当强缓存没有命中的时候,那么浏览器就会发送http请求到服务器,通过服务器依据资源的另外一些http头部去验证这个资源是否命中协商缓存,如果协商缓存命中,服务器就将这个请求返回,但是并不会返回这个资源的数据,而是告诉浏览器可以直接从缓存中读取这个资源,那么浏览器就会从缓存中读取这个资源

(3)强缓存和协商缓存的共同点:如果命中,那么都会从客户端的缓存中去读取资源,而不是从服务器中读取资源。不同的是,强缓存不会发送请求到服务器,而协商缓存则需要发送请求到服务器。

(4)如果协商缓存也没有命中的时候,浏览器直接从服务器中加载资源数据。

强缓存

当浏览器对某个资源的请求命中了强缓存时,返回的 http 状态为200,在 chrome 的开发者工具的 network 里面 size 会显示为 from cache

强缓存是利用 Expires 或者 Cache-Control 这两个 http response header 实现的,它们都用来表示资源在客户端缓存的有效期。

一,Expires

Expireshttp1.0 提出的一个表示资源过期时间的 header,它描述的是一个绝对时间,由服务器返回,用GMT格式的字符串表示,如:Expires:Thu, 31 Dec 2037 23:55:55 GMT,它的缓存原理是:

(1)浏览器第一次跟服务器请求一个资源的时候,服务器在返回这个资源的同时,会在 response 的 header 加上 Expiresheader,如

一,Expires

(2)浏览器在接收到这个资源后,会把这个资源连同所有的 response header 一起缓存下来(所有缓存命中的请求返回的 header 并不是来自服务器,而是来自之前缓存的 header

(3)浏览器再请求这个资源的时候,会先从缓存中去寻找,最好找到这个资源后,会拿当前的时间和Expire设置的时间比较,如果当前请求的时间在 Expires 指定的时间之前,那么就能命中缓存,否则不命中。

(4)如果缓存没有命中,那么浏览器直接从服务器中加载资源时,Expire Header 在重新加载的时候就会被更新。

弊端:Expires是较老的强缓存管理header,由于它是服务器返回的一个绝对时间,在服务器时间与客户端时间相差较大时,缓存管理容易出现问题,比如随意修改下客户端时间,就能影响缓存命中的结果。

所以在 HTTP1.1 的时候,就提出了一个新的header:Cache-Control,这是一个相对的时间,在配置缓存的时候以秒为单位,用数值表示,如:Cache-Control:max-age=315360000

二,Cache-Control

(1)浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在 responeheader 加上 Cache-Controlheader,如:

二,Cache-Control

(2)浏览器在接收到这个资源后,会把这个资源连同所有 response header 一起缓存下来;

(3)浏览器再请求这个资源时,先从缓存中寻找,找到这个资源后,根据它第一次的请求时间和 Cache-Control 设定的有效期,计算出一个资源过期时间,再拿这个过期时间跟当前的请求时间比较,如果请求时间在过期时间之前,就能命中缓存,否则就不行。(4)如果缓存没有命中,浏览器直接从服务器加载资源时,Cache-Control Header 在重新加载的时候会被更新。

Cache-Control 描述的是一个相对时间,在进行缓存命中的时候,都是利用客户端时间进行判断,所以相比较Expires,Cache-Control的缓存管理更有效,安全一些。这两个header可以只启用一个,也可以同时启用,当response header 中,ExpiresCache-Control 同时存在时,Cache-Control 优先级高于Expires

协商缓存

当浏览器对某个资源的请求没有命中强缓存,就会发一个请求到服务器,验证协商缓存是否命中,如果协商缓存命中,请求响应返回的http状态为304并且会显示一个Not Modified的字符串,比如你打开京东的首页,按f12打开开发者工具,再按f5刷新页面,查看 network,可以看到有不少请求就是命中了协商缓存的:

协商缓存

协商缓存是利用的是【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】这两对Header来管理的

一,【Last-Modified,If-Modified-Since】

(1)浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在respone的header加上 Last-Modified 的header,这个header表示这个资源在服务器上的最后修改时间:

Last-Modified

(2)浏览器再次跟服务器请求这个资源时,在request的header上加上 If-Modified-Since 的header,这个header的值就是上一次请求时返回的Last-Modified的值:

If-Modified-Since

(3)服务器再次收到资源请求时,根据浏览器传过来 If-Modified-Since 和资源在服务器上的最后修改时间判断资源是否有变化,如果没有变化则返回304 Not Modified,但是不会返回资源内容;如果有变化,就正常返回资源内容。当服务器返回304 Not Modified的响应时,response header中不会再添加 Last-Modified的header,因为既然资源没有变化,那么 Last-Modified 也就不会改变,这是服务器返回304时的 `response header :

header

(4)浏览器收到304的响应后,就会从缓存中加载资源。
(5)如果协商缓存没有命中,浏览器直接从服务器加载资源时,Last-ModifiedHeader在重新加载的时候会被更新,下次请求时,If-Modified-Since会启用上次返回的Last-Modified值。

弊端:【Last-Modified,If-Modified-Since】都是根据服务器时间返回的header,一般来说,在没有调整服务器时间和篡改客户端缓存的情况下,这两个header配合起来管理协商缓存是非常可靠的,但是有时候也会服务器上资源其实有变化,但是最后修改时间却没有变化的情况,而这种问题又很不容易被定位出来,而当这种情况出现的时候,就会影响协商缓存的可靠性。

所以就有了另外一对header来管理协商缓存,这对header就是【ETag、If-None-Match】。

二,【ETag、If-None-Match】

(1)浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在respone的header加上ETag的header,这个header是服务器根据当前请求的资源生成的一个唯一标识,这个唯一标识是一个字符串,只要资源有变化这个串就不同,跟最后修改时间没有关系,所以能很好的补充Last-Modified的问题:

Etag

(2)浏览器再次跟服务器请求这个资源时,在request的header上加上If-None-Match的header,这个header的值就是上一次请求时返回的ETag的值

If-None-Match

(3)服务器再次收到资源请求时,根据浏览器传过来If-None-Match和然后再根据资源生成一个新的ETag,如果这两个值相同就说明资源没有变化,否则就是有变化;如果没有变化则返回304 Not Modified,但是不会返回资源内容;如果有变化,就正常返回资源内容。与Last-Modified不一样的是,当服务器返回304 Not Modified的响应时,由于ETag重新生成过,response header中还会把这个ETag返回,即使这个ETag跟之前的没有变化:

new Etag

(4)浏览器收到304的响应后,就会从缓存中加载资源。

You forgot to set the business and currency_code for Paypal. Please set it in _config.yml.
You forgot to set the url Patreon. Please set it in _config.yml.
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×