- 为什么需要缓存?
- 什么是缓存?
- 缓存的原理:
- 缓存的分类
- 强制缓存
- Expires
- **expires的不足:**
- cache-Control
- cache-control的属性
- 协商缓存
- Last-Modified和If-Modified-Since
- **Last-Modified的不足**:
- ETag和If-None-Match
- **ETag的不足:**
- 缓存决策树
在任何一个前端项目中,访问服务器获取数据都是很常见的事情,但是如果相同的数据被重复请求了不止一次,那么多余的请求次数必然会浪费网络带宽,以及延迟浏览器渲染所要处理的内容,从而影响用户的使用体验。
如果用户使用的是按变量计费的方式访问网络,那么多余的请求还会隐性地增加用户的网络流量资费。
因此考虑使用缓存技术对已获取的资源进行重用,是一种提升网站性能与用户体验地有效策略。
浏览器缓存(Brower Caching)是浏览器对之前请求过的文件进行缓存,以便下一次访问时重复使用,节省带宽,提高访问速度,降低服务器压力
缓存的原理:缓存的原理是首次请求后保存一份请求资源的响应副本,当用户再次发起相同请求后,如果判断缓存命中则拦截请求,将之前存储的响应副本返回给用户,从而避免重新向服务器发起资源请求。
缓存的分类 强制缓存如果浏览器判断所请求的目标资源有效命中,则可以直接从强制缓存中返回请求响应和Status Code 200 OK,无须与服务器进行任何通信。
强缓存是利用http头中的Expires和Cache-Control两个字段来控制的,用来表示资源的缓存时间。
ExpiresExpires是在HTTP1.0协议中声名用来控制缓存失效日期的时间戳的字段,它由服务器端指定后通过响应头告知浏览器,浏览器在接收到带有该字段的响应体后进行缓存。
它的值是一个绝对时间的GMT格式的时间字符串。
比如网页的Expires值是:
expires:Web, 19 May 2022 10:47:02 GMT。
若之后浏览器再次发起相同的资源请求,便会对比expires与本地当前的时间戳,如果当前请求的本地时间戳小于expires的值,则说明浏览器缓存的响应还未过期,可以直接使用无须向服务器再次发起请求。只有当本地时间戳大于expires值发生缓存过期时,才允许向服务器重新发起请求。
expires的不足:从上述强制缓存是否过期的判断机制中不难看出,这个方式存在一个很大的漏洞,及对本地时间戳过分依赖,如果客户端本地的时间与服务器端的时间不同步,或者对客户端时间尽行主动修改,那么对于缓存过期的判断就可能无法与预期相符。
cache-Control为了解决expires判断的局限性,从HTTP1.1写于开始新增了cache-control字段来对expires的功能进行扩展和完善。
一般利用该字段的max-age来判断,这个值是一个相对时间。是一个以秒为单位的时间长度
例如:
Cache-Control:max-age=3600 //代表该资源在被请求到后的31536000秒内有效cache-control的属性
- no-cache和no-store
no-cache和no-store是两个互斥的属性值,不能同时设置。
no-cache:设置no-cache并非像字面上的意思不使用缓存,其表示为强制进行协商缓存,及对于每次发起的请求都不会再去判断强制缓存是否过期,而是直接与服务器协商来验证缓存的有效性,若缓存未过期,则会使用本地缓存。
no-store:设置no-store则表示禁止使用任何缓存策略,客户端的每次请求都需要服务器给予全新的响应。
- private 和 public
private和public也是cache-control的一组互斥属性,它们用以明确响应资源是否可被代理服务器进行缓存。
public:若资源响应头中的cache-control字段设置了public属性值,则表示响应资源既可以被浏览器缓存,又可以被代理服务器缓存。
private:private则限制了响应资源只能被浏览器缓存,若显示指定则默认值为private。
对于应用程序中不会改变的文件,你通常可以在发送响应头前添加积极缓存(public),这包括例如由应用程序提供的静态文件,例如图像,CSS文件和JavaScript文件。
这样可以减少性能和时间的消耗。
Cache-Control:public,max-age=31536000
- max-age和s-maxage
max-age:max-age属性值会比s-maxage更常用,它表示服务器端告知客户端浏览器响应资源的过期时长。在一般项目的使用场景中基本够用,对于大型架构的项目通常会涉及使用各种代理服务器的情况,这就需要考虑缓存在代理服务器上的有效性问题。这便是s-maxage存在的意义。
s-maxage:s-maxage表示缓存在代理服务器中的过期时长,当且仅当设置了public属性值时才有效。
由此可见,cache-control能作为expires的完全替代方案,并且拥有其所不具备的一些缓存控制特性,在项目实践中使用它就足够了,目前expires还存在的唯一理由是考虑可用性方面的向下兼容
协商缓存顾名思义,协商缓存就是在使用本地缓存之前,需要向服务器端发起一次get请求,与之协商当前浏览器保存的本地缓存是否已经过期。
协商缓存是由服务器确定缓存资源是否可用。主要涉及到两组header字段:
- Etag和If-None-Match
- Last-Modified和If-Modified-Since
浏览器第一次请求一个资源的时候,服务器返回的header中会加上Last-Modified,Last-modified是一个时间标识该资源的最后修改时间,例如Last-Modified: Thu,31 Dec 2037 23:59:59 GMT。
当浏览器再次请求该资源时,request的请求头中会包含If-Modified-Since,该值为缓存的之前返回的Last-Modified。服务器收到If-Modified-Since后,根据资源的最后修改时间判断是否命中缓存。如果命中缓存,则返回304,并且不会返回资源内容,不会返回Last-Modified。
Last-Modified的不足:- 首先它只是根据资源最后的修改时间戳进行判断的,如果请求的文件资源进行了重命名,但内容并没有发生变化,时间戳也会更新,从而导致协商缓存时关于有效性的判断验证为失效,需要重新进行完整的资源请求。这无疑会造成网络带宽资源的浪费,以及延长用户获取到目标资源的时间。
- 其次表示文件资源修改的时间戳单位是秒,如果文件修改的速度非常快,假设在几百毫秒内完成,那么上述通过时间戳的方式验证缓存的有效性,是无法识别出该次文件资源的更新的。
其实引起上述两种缺陷的原因相同,就是服务器无法仅依据资源修改时间戳来识别出真正的更新,进而导致重新发起了请求或者不发起请求,导致缓存bug的出现。
ETag和If-None-Match为了弥补通过时间戳判断的不足,从HTTP1.1规范开始新增了一个ETag的头信息,即实体标签(Entity Tag)。
Etag主要是服务器为不同资源进行哈希运算所生成的一个字符串,该字符串类似于文件指纹,只要文件内容编码存在差异,对应的ETag就会不同,因此可以使用ETag对文件资源进行更精准的变化感知。
不像强制缓存中cache-control可以完全替代expires的功能,在协商缓存中ETag并非last-modified的替代方案而是一种补充方案,因为它依旧存在一些弊端
ETag的不足:-
一方面服务器对于生成文件资源的ETag需要付出额外的计算开销,如果资源的尺寸较大,数量较多且修改比较频繁,那么生成ETag的过程就会影响服务器的性能。
-
另一方面ETag字段值的生成分为强验证和弱验证。
强验证根据资源内容进行生成,能够保证每个字节都相同;
弱验证则根据资源的部分属性值来生成,生成速度快但无法确保每个字节都相同,并且在服务器集群场景下,也会因为不够准确而降低协商缓存的有效验证的成功率,所以恰当的方式是根据具体的资源使用场景选择恰当的缓存校验方式。



