一、前方
通过网络请求资源缓慢并且降低了客户端的用户体验,增添了服务端的负担。很多短期之内不会经常发生变化的资源文件没必要每次访问都想服务端进行数据请求,而缓存策略的使用就是为了改善客户端的呈现时间,降低服务端的负担。
二、缓存规则及解析
为方便理解,假设浏览器存在一个缓存数据库,用于存储缓存信息。在客户端第一次请求数据时,此时缓存数据库中没有对应的缓存数据,需要请求服务器,服务器返回后,将数据存储至缓存数据库中,如下图:
根据是否需要重新向服务器发起请求分类,将HTTP缓存规则分为两在类(强制缓存,对比缓存「也叫协商缓存」):
(1)已存在缓存数据时,仅基于强制缓存,请求数据的流程如下所示:
(2)已存在缓存数据时,仅基于协商缓存,请求数据流程如下:
我们可以看到两种缓存规则的不同,强制缓存如果生效,不需要再和服务器发生交互,而协商缓存不管是否生效,都需要与服务端发生交互。
两类缓存规则可以同时存在,强制缓存优先级高于协商缓存,也就是说,当执行强制缓存的规则时,如果缓存生效,直接使用缓存,不再执行协商缓存规则。
三、缓存常用字段
强制缓存方案:
1、Cache-Control 作为请求头字段
1.1 Cache-Control:no-cache
使用 no-cache 指令的目的是为了防止从缓存中返回过期的资源。客户端发送的请求中如果包含no-cache 指令,则表示客户端将不会接收缓存的资源,每次请求都是从服务器获取资源,返回304
1.2 Cache-Control: no-store
使用no-store指令表示请求的资源不会被缓存,下次任何其它请求获取该资源,还是会从服务器获取,返回200,即资源本身。
2、Cache-Control 作为响应头字段
2.1 Cache-Control:public
当指定使用 public 指令时,则明确表明其他用户也可以利用缓存
2.2 Cache-Control:private
当指定 private 指令后,响应只以特定的用户作为对象,这与 public 指令的行为相反,缓存服务器会对该特定用户提供资源缓存的服务,对于其他用户发送过来的请求,代码服务器则不会返回缓存。
2.3 Cache-Control:no-cache
每次客户端请求,必须先向服务器确认其有效性,如果资源没有更改,则返回 304,
2.4 Cache-Control :no-store
不对响应的资源进行缓存,即用户下次请求还是返回200,返回资源本身
2.5 Cache-Control:max-age=60800(单位:秒)
资源缓存在本地浏览器的时间,如果超过该时间,则重新向服务器获取
协商缓存方案:
1、请求头部字段 & 响应头部字段
1.1 请求头部字段
1.2 响应头部字段
注意:If-None-Match 的优先级比 If-Modified-Since高,所以两者同时存在,遵从前者。
四、强缓存与协商缓存
缓存的优点:
1、减少了少必要的数据传输,节省带宽
2、减少服务器的负担,提升网站性能
3、加快了客户端加载网页的速度
4、用户体验友好
缓存的缺点:
1、资源如果有更改但是客户端不及时更新会造成用户获取信息滞后,如果老版本有BUG的话,情况会更坏,
所以为了避免设置缓存错误,掌握缓存的原理对于我们工作中去更加合理的配置缓存是非常重要的
强制缓存的总结:
1、cache-control:max-age=xxx,public
客户端和代理服务器都可以缓存该资源
客户端在xxx秒的有效期内,如果有请求该资源的需求的话就直接读取缓存,statu code:200,如果用户做了刷新操作,就向服务器发起http请求
2、cache-control:max-age=xxx,private
只让客户端可以缓存该资源,代理服务器不缓存
客户端在xxx秒内直接读取缓存,statu code:200
3、cache-control:max-age=xxx,immutable
客户端在xxx秒的有效期内,如果有请求该资源的需求的话就直接读取缓存,statu code = 200 即使用户做了刷新操作,也不会向服务器访问请求
4、cache-control:no-cache
路过设置强缓存,但是不妨碍设置协商缓存; 一般如果做了强缓存,只有在强缓存失效了才走协商缓存,设置了 no-cache 就不会走强缓存了,每次请求都会询问服务端
5、cache-control:no-store
不缓存,这个会让客户端、服务端都不缓存,也就是没有所谓的强缓存 、协商缓存了
如何设置协商缓存:
1、responseHeader 里面的设置 etag:'xxxxxx' ; last-modified: time
etag:每个文件只有一个,改动了就变了,表示文件的hash,每个文件唯一
last-modified:文件的修改时间,精确到秒
也就是说,每次请求返回来 responseHeader 中的etag和 last-modified ,在下次请求时在 requestHeader 把这两个带上,服务端把你带过来的标识进行对比,然后判断资源是否更改了,如果更改了直接返回新的资源,和更新对应的 responseHeader 的标识 etag / last-modified,如果资源没有变,那就不变etag / last-modified ,这时候对客户端来说每单位名称请求都要进行协商缓存 ,请求流程如下:
发请求 > 看资源是否过期 > 过期 > 请求服务器 > 服务器对比资源是否真的过期 > 没过期 > 返回304状态码 > 客户端用缓存 的老资源
协商缓存步骤总结:
1、请求资源时,把用户本地该资源的etag同时带到服务端,服务端和最新资源做对比
2、如果资源没改,返回304,浏览器读取本地缓存
3、如果资源有改,返回200 , 返回最新的资源
注:responseHeader中的 etag/last-modified 在客户端重新向服务端发起请求时,会在 requestHeader中换个Key名:
etag --> if-noni-matched
last-modified ---> if-modified-since
扩展:serviceWorker:浏览器背后的独立线程,一般可以用来实现缓存功能,使用serviceWorker必须用HTTPS,因为它涉及到请求拦截
五、总结
1、对于强制缓存,服务器通知浏览器一个缓存时间,下次请求直接用缓存,不在时间内,执行协商缓存策略
2、对于协商缓存,将缓存信息中的 Etag 和 Last-Modified 通过请求发送给服务器,由服务器校验 ,返回304状态,浏览器直接使用缓存