🌻 前言
前几天我工作比较闲,就想着看看我司的前端项目有什么可以性能优化的点。于是乎在一个h5项目里,发现没有配置缓存策略。我找到架构组的同学,说明了这个问题。
因为此项目是部署在腾讯云服务器上的,在腾讯云管理后台支持配置缓存策略。
配置缓存策略后,平均每个页面FP缩小了有200ms(因为这个h5项目采用的是gulp工作流,几乎每个页面都是单页面,本身FP就很快,所以效果肉眼几乎观察不出区别),nice,前端程序员的价值又体现了~(可惜我做的一些性能优化领导不知道,我这人比较腼腆,不善表达🥺)
🌈 概述
🍀 强制缓存
强制缓存:设置缓存机制后,前端第一次请求到资源会把资源缓存到客户端,如果下次请求时资源没有过期,那么直接调用本地缓存的资源,如果过期则重新发送请求。
关键点 >>>
-
强制缓存由服务端开启,利用
http头
中的Expires
和Cache-Control
两个字段来控制 -
客户端设置请求头
Cache-Control
,只有为:no-store
、no-cache
、max-age=0
才会生效(也就是客户端不想走强制缓存的时候生效。no-cache意思是不走强缓存,走协商缓存;no-store意思是不使用缓存),除非后端对这个字段做了处理; -
强制缓存不用和服务端交互;
-
强缓存返回状态码为200;
-
post请求不能设置缓存,只有get请求有效。
补充说明 >>>
Expires
:response header里的过期时间,浏览器再次加载资源时,如果在这个过期时间内,则命中强缓存(http1.0的产物,现在一般用cache-control)。
例如: expires: Thu, 03 Jan 2019 11:43:04 GMT
它是一个时间戳(准确点应该叫格林尼治时间), 当客户端再次请求该资源的时候, 会把客户端时间与该时间戳进行对比, 如果大于该时间戳则已过期, 否则直接使用该缓存资源。
但是, 有个大问题, 发送请求时是使用的客户端时间去对比。一是客户端和服务端时间可能快慢不一致, 另一方面是客户端的时间是可以自行修改的(比如浏览器是跟随系统时间的, 修改系统时间会影响到), 所以不一定满足预期。
Cache-Control
:cache-control主要有max-age和s-maxage、public和private、no-cache和no-store等值。例如当值设为max-age=300时,则代表在这个请求正确返回时间(浏览器也会记录下来)的5分钟内再次加载资源,就会命中强缓存。
图1.1 强缓存的响应头
图1.2 强缓存不和服务器交互,请求时间为0ms
- 控制台设置停用缓存其实就是在
http 头
里设置了cache-control: no-cache
图1.3 控制台停用缓存
🍀 协商缓存
协商缓存:第一次请求资源时,服务器会返回资源以及资源标识,当下次请求时,会对比资源标识,如果一致,则只返回状态码304,不用返回资源,如果不一致,则会返回资源和新的资源标识。
协商缓存主要依赖的响应头包括last-modified
和ETag
。
关键点 >>>
-
协商缓存需要和服务器交互;
-
请求资源命中协商缓存后,返回的状态码为
304
,所以304状态码不应该认为是一种错误,而是对客户端有缓存情况下服务端的一种响应;
响应头说明 >>>
last-modified
记录资源最后修改的时间。启用后, 请求资源之后的响应头会增加一个last-modified字段, 如下:
last-modified: Thu, 20 Dec 2018 11:36:00 GMT
但last-modified有以下两个缺点:
- 🔥 只要编辑了, 不管内容是否真的有改变, 都会以这最后修改的时间作为判断依据, 当成新资源返回, 从而导致了没必要的请求相应, 而这正是缓存本来的作用即避免没必要的请求
- 🔥 时间的精确度只能到秒, 如果在一秒内的修改是检测不到更新的, 仍会告知浏览器使用旧的缓存
ETag
的出现就是为了解决last-modified的上述问题。ETag
会基于资源的内容编码生成一串唯一的标识字符串, 只要内容不同, 就会生成不同的ETag。启动ETag之后, 请求资源后的响应返回会增加一个ETag字段, 如下:
ETag: "ALJlkaasdkljasldjLSAJDakl_"
图2.1 缓存机制为协商缓存时首次进入页面的响应头
图2.2 第二次进入页面命中协商缓存后响应头
图2.2 图2.3 命中协商缓存后会发送请求,并且响应状态码为304
🌈 常用缓存策略
🍀 html:no-cache
🍀 js文件:max-age=2592000(一个月),s-maxage=86400;文件命名带版本号或指纹信息,方便及时更新。
🍀 CSS文件:max-age=2592000,s-maxage=3600;文件命名带版本号或指纹信息,方便及时更新。
图片:max-age=15552000;文件命名带版本号或指纹信息,方便及时更新。
🍀 XHR请求: no-cache
(s-maxage的优先级比max-age高。s-maxage是代理服务器的缓存时间)
🌈 如何配置缓存策略
🍀 前端配置缓存
-
前端配置缓存只能设置html文件的缓存,对网页中的图片,js文件等其他静态资源无法配置,需要在nginx等服务器站点配置。
-
html页面设置缓存是在
<head>
标签中嵌入<meta>
标签,如下:
//禁用缓存如下:
<meta http-equiv="pragma" content="no-cache">
// 仅有IE浏览器才识别的标签,不一定会在请求字段加上Pragma,但的确会让当前页面每次都发新请求
<meta http-equiv="cache-control" content="no-cache">
// 其他主流浏览器识别的标签
<meta http-equiv="expires" content="0">
// 仅有IE浏览器才识别的标签,该方式仅仅作为知会IE缓存时间的标记,你并不能在请求或响应报文中找到Expires字段
//设置缓存如下:
<meta http-equiv="Cache-Control" content="max-age=7200" />
// 其他主流浏览器识别的标签
<meta http-equiv="Expires" content="Mon, 20 Aug 2018 23:00:00 GMT" />
// 仅有IE浏览器才识别的标签
🍀 nginx配置示例
静态资源的缓存一般是在web服务器上配置的,常用的web服务器有:nginx、apache。这里列举下nginx的配置示例,具体location匹配正则规则,请按照自己项目需要进行匹配。
//示例1:强缓存时效为30s,30s后默认使用协商缓存,此时缓存时效优先级 > max-age
location / {
add_header Cache-Control max-age=60;
root html;
index index.html index.htm;
expires 30s;
}
//示例2: 只使用协商缓存
location / {
# no-cache 禁用强缓存
add_header Cache-Control no-cache;
root html;
index index.html index.htm;
}
//示例3: 强缓存 缓存时效 1小时
location / {
root html;
index index.html index.htm;
expires 1h;
}