共计 2320 个字符,预计需要花费 6 分钟才能阅读完成。
浏览器虽然发现了本地有该资源的缓存,但是不确定是否是最新的,于是想服务器询问,若服务器认为浏览器的缓存版本还可用,那么便会返回 304。
强缓存和协商缓存。
1. 浏览器请求某资源,通过 header 判断是否强缓存,若是强缓存,则从本地直接获取缓存文件,不发请求到浏览器 2. 若不是强缓存,发送请求到服务器,服务器通过一些 request header 确定是否是协商缓存,如果是,服务器将请求返回,但不返回资源,而是让客户端从本地缓存获取资源 3. 强缓存和协商缓存,资源都是本地,只是强缓存不会发送请求到服务器,协商缓存会发送请求到服务器。4. 不是协商缓存,则浏览器将资源发送客户端。
强缓存:服务端第一次响应请求时,告知浏览器还存在本地,设定时间,时间之内还获取该资源就从本地获取。Expires Cache-Control 两个响应首部字段告知过期时间和最大生命周期。再次请求从缓存中找资源,若请求时间比 Expires 设定时间早则可用本地资源。http1.1 Cache-Control 缓存资源最大生命周期,秒为单位。一起使用以 Cache-Control 为主。协商缓存:文件最后修改时间,服务器判断资源是否更新,未更新返回 304 表示 not modified,浏览器从缓存加载。LastModified:资源最后更新时间,随服务器返回。if-modified-Since 请求首部字段,通过比较两个时间判断资源是否修改。没有修改则协商缓存。
过程描述:
1. 浏览器第一次请求资源,服务器响应,返回资源,响应头加 Last-Modified。2. 浏览器再次请求资源,在请求头加上 if modified since,该值为上次 Last-Modified 的值 3. 服务器接受请求,将 ifmodifiedsince 值和资源最后修改值做对比,若一致则返回 304,协商缓存。
Etag 周期性重写资源,但资源没变化,加注释等无关紧要信息。用 Etag 区分两个资源是否一致,随 response 返回和请求头的 if-none-match 相比较,判断资源在两次请求中是否修改,未修改则协商缓存。
还有三种缓存方式:application cache,cookie,localstorage,sessionstorage
那么,前端怎么实现呢?
了解 ifModified
ifModified (Boolean) : (默认: false) 仅在服务器数据改变时获取新数据。使用 HTTP 包 Last-Modified 头信息判断。
由 ifModified 的定义可知,当 ifModified 设为 true 时,请求头会加上 If-Modified-Since, If-Modified-Since 是标准的 http 请求头标签,在发送 http 请求时,把浏览器端缓存页面的最后修改时间一起发到服务器去,服务器会把这个时间与服务器上实际文件的最后修改时间进行比较。如果时间一致,那么返回 http 状态码 304(不返回文件内容)如果时间不一致,就返回 http 状态码 200 和新的文件内容,客户端接到之后,会丢弃旧文件,把新文件缓存起来,并显示到浏览器中。
了解 Last-Modified
Last-Modified: 表示该文件的最后修改日期, 是文件属性和服务端没关系对于静态资源文件这是一个很有用的属性, 请求静态资源文件时, 请求头会携带一个 If-Modified-Since:xxx(时间) 属性, 该属性是上一次请求时获取到的 Last-Modified 时间, 如果本次请求的请求头时间与响应头时间一致, 则返回 304 状态码, 告诉浏览器你当前拥有的页面是最新的不需要获取新的数据
实现
function getAjax(url, sendData, state = true) {
return new Promise((resolve, reject) => {
$.ajax({
url: url,
data: sendData,
type: ‘get’,
dataType: ‘json’,
cache: !state, // 是否使用浏览器的缓存数据
ifModified: state,// 是否向服务器询问数据更新情况
success(data, des, status) {
if (status.status === 200) {
if (data.code === 200) {
return resolve(data.data);
} else {
return reject({code: data.code, message: data.message});
}
}
if (status.status === 304) {
getAjax(url, sendData, false)
.then(data => {
resolve(data);
})
.catch(data => {
reject(data);
});
}
}, error() {
return reject({code: 503, message: ‘ 数据无法加载,请刷新重试!’});
}
});
});
}
分析
getAjax 中传入 3 个参数,url 接口地址,sendData 传输的数据,state 状态值【代表 ifModified 的状态】
首先向后台询问数据是否更新,ifModified 的状态为 true,不使用浏览器的缓存数据,cache 设 false
当 http 状态码返回 200 时,说明数据更新了,直接使用服务器传输过来的新数据;
当 http 状态码返回 304 时,说明数据没有发生改变,服务器不返回新数据,则向浏览器缓存请求数据,此时 cache 设 true,ifModified 的状态为 false,不需要询问服务器数据是否更新。
总结:使用缓存的目的就是在于减少计算,IO,网络等时间,可以快速的返回,特别是流量比较大的时候,可以节约很多服务器带宽和压力。