浏览器缓存在前端性能优化是个非常重要的点,第一次接触强缓存和协商缓存的概念的时候也是一头雾水,经过一轮面试背诵加理解终于有点感悟,希望以下的梳理对你有一定帮助。
缓存:
缓存是一种保存资源副本并在下次请求时直接使用该副本的技术。当 web 缓存发现请求的资源已经被存储,它会拦截请求,返回该资源的拷贝,而不会去源服务器重新下载。
优点:缓解服务器端压力,提升性能(减少网页加载速度),提高用户体验。
浏览器缓存:
浏览器缓存是浏览器在本地对用户最近请求过的文档进行存储,当访问者再次访问同一页面时,若文件未过期或未修改(下面我们用新鲜一词代替,感觉挺形象的),浏览器就可以直接从本地加载文档。
而强缓存和协商缓存就是判断文件是否新鲜从而决定本次请求的资源要直接从本地获取还是去服务器重新下载的具体实现。
请求资源时浏览器怎么知道是强缓存还是协商缓存?
用户首次请求并获取到该资源后,根据返回的信息来告诉如何缓存资源,可能采用的是强缓存,也可能告诉客户端浏览器是协商缓存,这都需要根据响应的header内容来决定。
强缓存:
(1)过程
用户请求访问过的资源,浏览器拦截请求,查看该资源的强缓存相关header字段来判断资源是否过期,若未过期即命中强缓存,直接从本地获取资源来展示给用户,若没有命中强缓存,则从服务器重新加载资源或进入协商缓存流程(如果资源同时设置了强缓存和协商缓存)
(2)相关header字段
Expires: 一个未来时间,浏览器再次加载资源时,如果在这个过期时间内,则命中强缓存。
Expires:
Thu , 15 Apr 2030 20:00:00 GMT //代表 2030 年4月15日请求过期,在这之前当前请求都有效。
Cache-Control: 当值设为max-age=300时,则代表在这个请求正确返回时间(浏览器也会记录下来)的5分钟内再次加载资源,就会命中强缓存。
cache-control除了该字段外,还有下面几个比较常用的设置值:
no-cache:不使用本地缓存。需要使用缓存协商,先与服务器确认返回的响应是否被更改,如果之前的响应中存在ETag,那么请求的时候会与服务端验证,如果资源未被更改,则可以避免重新下载。
no-store:直接禁止浏览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源。
public:可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器。
private:只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存。
注: 同时设置时 cache-control 优先级高于 expires
协商缓存:
(1)过程
用户请求访问过的资源,请求头携带相关header字段去跟服务器的对应相关header字段做对比,由服务器判断资源是否修改,没有修改则命中协商缓存,服务器返回304状态码,不返回资源,浏览器获取本地资源。若资源修改,则返回200状态码并返回新的资源和Last-Modified和Etag。
(2)相关header字段
If-Modified-Since对应Last-Modified:
浏览器第一次请求一个资源的时候,服务器返回的header中会加上Last-Modify,Last-modify是一个时间标识该资源的最后修改时间;当浏览器再次请求该资源时,request的请求头中会包含If-Modify-Since,该值为缓存之前返回的Last-Modify。服务器收到If-Modify-Since后,根据资源的最后修改时间判断是否命中缓存.
If-None-Match对应Etag:
浏览器第一次请求一个资源的时候,服务器返回的header中会加上Etag,Etag是一个标识该资源的hash值;当浏览器再次请求该资源时,request的请求头中会包含If-None-Match,该值为缓存之前返回的Etag。服务器收到后,If-None-Match根据资源的最新的Etag判断是否命中缓存.
Last-Modified和Etag的区别:
(1) Etag要优于Last-Modified。Last-Modified的时间单位是秒,如果某个文件在1秒内改变了多次,那么他们的Last-Modified其实并没有修改,但是Etag每次都会改变确保了精度.
(2) 在性能上,Etag要逊于Last-Modified,毕竟Last-Modified只需要记录时间,而Etag需要服务器通过算法来计算出一个hash值;
(3) 在优先级上,服务器校验优先考虑Etag。
(4) 与 Last-Modified/If-Modified-Since 不同的是,返回 304 时,ETag 还是会重新生成返回至浏览器。
(5) 有些文件可能会周期性更改,但内容并没有修改时,用 Etag 就不用重新拉取.
注: Last-Modified和Etag同时使用
强缓存和协商缓存的区别:
可以这样理解:强缓存是浏览器(判断是否命中后)单方做决定是否向服务器发起请求,比较强势,若命中则不会与服务器进行任何通信.而协商缓存是浏览器与服务器(相关字段的校对)双方协商是否返回新资源.
一般将一些不常更新的静态资源设置强缓存加协商缓存,而类似index.html等更新频繁的资源设置为协商缓存.
无视强缓存或协商缓存的一些操作:
(1)点击刷新按钮或者按F5
浏览器直接判断本地的缓存文件过期,但是会带上If-Modifed-Since,If-None-Match, 这就意味着服务器会对文件检查新鲜度,返回结果可能是304,也有可能是200。即直接无视强缓存进行协商缓存。
(2)用户按Ctrl+F5(强制刷新)
浏览器不仅会对本地文件过期,而且不会带上 If-Modifed-Since,If-None-Match,相当于之前从来没有请求过,返回结果是200。即直接无视强缓存和协商缓存。
参考文章: