在工作中,前端代码打包之后的生成的静态资源就要发布到静态服务器上,这时候就要做对这些静态资源做一些运维配置,其中,gzip和设置缓存是必不可少的。这两项是最直接影响到网站性能和用户体验的。
缓存的优点:
- 减少了不必要的数据传输,节省带宽
- 减少服务器的负担,提升网站性能
- 加快了客户端加载网页的速度
- 用户体验友好
缺点:
- 资源如果有更改但是客户端不及时更新会造成用户获取信息滞后,如果老版本有bug的话,情况会更加糟糕。
强制缓存与协商缓存
浏览器缓存静态资源实际上是通过 HTTP 协议缓存策略,有两种策略分别是强制缓存和协商缓存。
强制缓存:会根据过期时间判断是使用本地缓存还是请求新的资源。
协商缓存:每次都会发出请求,经过服务器对比之后决定采用本地缓存还是新的资源。
使用哪种缓存策略是通过 HTTP 协议的 header 信息决定。
二、强制缓存:Expires 和 Cache-control
Expires 和 max-age 是强制缓存的关键的信息,都会在 http 响应的 header 信息。
1.Expires
Expires 是通过指定一耳光明确的时间点作为缓存资源的过期时间,在这个时间之前,客户端都是使用本地缓存的文件来响应 HTTP 请求,不会向服务器发出实体请求不过调试的时候能够发现这个请求,并且这个请求是 200
Expires 的优点:
- 在缓存过期时间内减少客户端的 HTTP 请求,不仅节省客户端处理时间和提高 Web 应用执行速度,也减少了服务器负载以及客户端网络资源的损耗
Expires 的 header 信息示例:
Expires:Wed, 23 Aug 2019 14:00:00 GMT
上面的意思是缓存过期时间是 2019年8月23日 14:00:00
Expires 的 缺点:
- 指定的时间是以服务端为准但是客户端进行过期判断时是将本地的时间和这个时间进行对比
- 如果客户端端时间和服务端时间存在差异,则会存在问题
2.Cache-control
为了解决 Expires 的缺点,HTTP 1.1 增加了新的 header 字段 Cache-control
来更精准的控制缓存常用的 Cache-control 信息有下面几个:
Cache-Control 的几个取值含义:
private: 仅浏览器可以缓存
public: 浏览器和代理服务器都可以缓存(对于private和public,前端可以认为一样,不用深究)
max-age=xxx 过期时间(重要)
no-cache 不进行强缓存(重要)
no-store 不强缓存,也不协商缓存,基本不用,缓存越多才越好呢
从请求的时刻开始计算,能够控制最长保留多久,单位是 s
。
比如 max-age=3600
表示浏览器在1小时内使用缓存,不会发送实体请求到服务器。
相比于 Expires ,max-age 通过控制时间长度而不需要与服务端时间戳进行计算,控制的更加精准,没有时间误差。
3、没有指定 no-cache 的缓存判断流程图
注意
这里有个问题,就是 max-age = 0 ,和 no-cache 有啥区别,我理解的是,no-cache直接不进行强缓存,让你去走协商缓存,而max-age=0是进行强缓存,但是过期了,需要更新。。。虽然实际上看起来两者效果是一样的。
三、协商缓存
Etag 是服务器给资源分配的字符串形式唯一性标识,作为响应的 header 信息返回给浏览器,浏览器在
Cache-control指定
no-cache 或者是 max-age
和 expires
都过期的情况下,将 Etag 值通过 If-none-match
作为请求首部信息发送给服务器,服务器接收到请求之后,对比锁清秋资源的 Etag 值是否改变:
- 如果没改变,会返回
304 Not Modified
,并且根据之前的缓存策略分配新的 Cache-control 信息 - 如果发生了改变,会返回新的资源并且分配新的 Etag
如果要强制使用协商缓存,则需要将 Cache-control 设置为 no-cache,这样不回去判断 max-age 和 Expires ,每次都会经过服务器的 Etag 对比。
协商缓存并非比强制缓存低级,而是要看使用场景,在 HTML 文件场景下,如果一个 URL www.example.com/index.html
其中 index.html
是不能强制缓存的,因为要保证内容的实时更新,因此必须使用协商缓存
缓存命中显示
- 从服务器获取新的资源
- 命中强缓存,且资源没过期,直接读取本地缓存
- 命中协商缓存,且资源未更改,读取本地缓存
其他
怎么配置资源的缓存规则
可以有后端服务器配置,也可以在nginx中配置,稍后会更新一张nginx的配置
实际应用
用vue-cli打包后生成的单页文件是有一个html,与及一堆js css img资源,怎么去设置这些文件呢,核心需求是:
- 要有缓存,毋庸置疑
-
当发新包的时候,要避免加载老的缓存资源
我的做法是:
index.html文件采用协商缓存,理由就是要用户每次请求index.html不拿浏览器缓存,直接请求服务器,这样就保证资源更新了,用户能马上访问到新资源,如果服务端返回304,这时候再拿浏览器的缓存的index.html,切记不要设置强缓存!!!其他资源采用强缓存 + 协商缓存
-
vue 项目,脚手架已经将更改的文件做 hash 处理了,因此一般的 js、css 文件不需要我们再去操作。
而对于 index.html,我们需要在 nginx 上做 no-store 处理,即完全不缓存 index.html,每次都请求最新的html。。。因为 html 中会外链 css、js,如果我 html 还是走的缓存,那链接的还是老的 css 啊,想想???