前端缓存知识介绍
缓存分为强缓存和协商缓存;
缓存的好处有很多,比如:减轻服务器的压力、快速响应、减轻网络压力、为用户节省流量等
缓存有时候也会有一些问题:比如:客户端不能获取到最新的资源,导致部署升级失败,但是现在这个已经不是问题,通过打包构建工具可以解决,文章最后会有对应的解决原理解析。
强缓存
强缓存使用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