前端缓存知识介绍
缓存分为强缓存和协商缓存;
缓存的好处有很多,比如:减轻服务器的压力、快速响应、减轻网络压力、为用户节省流量等
缓存有时候也会有一些问题:比如:客户端不能获取到最新的资源,导致部署升级失败,但是现在这个已经不是问题,通过打包构建工具可以解决,文章最后会有对应的解决原理解析。
强缓存
强缓存使用Expires
、Cache-Control
两个响应头字段,同时存在时Cache-Control
的优先级更高。
命中强缓存时,客户端不会去服务器请求资源,而是直接从缓存中读取内容,返回HTTP
状态码200
。
Expires
出现在响应头中,代表该资源的过期时间,是一个GMT格式的标准时间
客户端第一次请求服务端的时候,服务端会返回资源和响应头 Expires
,表示资源的具体过期时间。
如果在过期时间内,客户端又去请求该资源,则命中缓存,直接使用缓存中的,不去请求服务端了。
Expires
需要优化地方
- 缓存时间过期以后,不管资源有没有更新都固定去服务端请求一次,不灵活。
- 缓存过期时间是一个具体的时间,这个时间依赖于客户端的时间,如果不准确或者被人为改动,会影响缓存命中。
Cache-Control
出现在请求/响应头中,通过不同的属性控制不同的缓存策略
响应头的属性有
max-age
:在多少秒内有效,是一个相对时间s-maxage
:在缓存服务器上缓存的有效时间,只对public
有效no-cache
:不使用本地缓存,需使用协商缓存no-store
:不使用缓存,每次都会重新从服务端下载资源public
:可以被客户端/中间代理服务器缓存private
:可以被客户端缓存,不可以被中间代理服务器缓存,默认值
请求头的属性有
max-stale: 5
表示客户端获取代理服务器缓存时,超过过期时间5秒之内都是可以的min-fresh: 5
表示客户端获取代理服务器缓存时,需要在过期时间5秒之前才行only-if-cached
表示只获取代理服务器缓存,代理服务器缓存过期则返回504报错
协商缓存
协商缓存主要有两组四个头字段,两两配合使用,If-Modified-Since
和Last-Modified
,Etag
和If-None-Match
,Etag
和If-None-Match
的优先级高。
If-Modified-Since
和 Last-Modified
:
If-Modified-Since
: 请求头,资源最近修改时间,由浏览器高速服务器,是浏览器第一次访问服务器时返回的Last-Modified
值Last-Modified
:响应头,资源最近修改时间,由服务器告诉浏览器
服务器接收到请求后会根据此字段值判断是否使用缓存;使用缓存,则返回304;不使用缓存则返回新文件给客户端并更新Last-Modified响应头字段的值。
Etag
和 If-None-Match
:
If-None-Match
:请求头,缓存资源标识,由浏览器告诉服务器,是浏览器第一次访问服务器返回的Etag
值Etag
:响应头,资源标识,由服务器告诉浏览器
服务器接收到请求后会比较这两个值是否一样,一样就返回304,让客户端从缓存中读取,不一样就会返回新文件给客户端并更新Etag响应头字段的值。
缓存位置
内存memory cache
、硬盘disk cache
、Service Workers
缓存配置
// 缓存时间1个月
add_header Cache-Control 'public, max-age=2592000'
// 使用协商缓存
add_header Cache-Control 'public, no-cache'
解决缓存引发的问题
缓存引发的问题就是最新资源不能及时更新,客户端在缓存有效期内显示的不是最新的资源。我们可以使用构建工具入Webpack等根据文件名/文件内容自动计算hash
值来给文件命名,当内容或文件名发生改变的时候,构建出来的文件名也一定会不一样,这样也解决了强缓存还在有效期内的问题。
注意事项
- F5 会跳过强缓存规则,直接走协商缓存。
- CTRL + F5 会跳过所有缓存规则,和第一次请求一样。
- 项目中大多对HTML进行协商缓存,对CSS\JS\图片进行强缓存,文件名带上Hash。
- 强缓存是客户端在发起请求前,在客户端进行的是否使用缓存的判断;协商缓存是服务端收到客户端请求后,在服务端进行的是否使用缓存的判断。
- 命中强缓存则不会发请求去服务端;协商缓存是会对服务端请求的,协商缓存命中成功只返回响应头,协商缓存命中失败则返回最新的资源。
- 命中强缓存时,返回状态码是200;命中协商缓存时,返回状态码是304