浏览器缓存是优化网站,提升网站性能的有效方法。
浏览器缓存一般指对服务器返回静态资源(html、js、css文件,图片,数据)在客户端的备份。(不考虑ajax请求)
👇基于Chrome浏览器版本 78.0.3904.97(正式版本);firefox默认过期时间都是0,设置其他值也无效。
1. 浏览器强制缓存
在服务端返回的Cache-Control或者Expires到期之前,不向服务器发送请求。直接从缓存取数据。
1. http1.0对应的header
通过HeaderEditor的Chrome插件模拟实现。
1. 请求头字段(Request Header)
/*** Pragma决定是否允许资源缓存;*****/
Pragma: no-cache
// 对于index.html只设置这一个字段,就不允许缓存
// 对于js/css文件来说,如果没有设置Cache-Control,根据响应头判断
// ⚠️开发者工具中的Disable Cache开启后,浏览器自动设置
Pragma: no-cache;
Cache-Control: no-cache;
2. 响应头字段(Response Header)
该字段默认不添加;
Expires: new Date(...) //GMT格式时间
// 表示允许缓存,且指定了缓存资源的过期时间
// 当没有Cache-Control时,该字段起作用,API在过期时间内从缓存取值
// 如果响应头中出现Cache-Control,该字段直接被忽略
2. http1.1对应的Header
1. 请求头字段(Request Header)
//指定不允许缓存资源
Cache-Control: no-cache;
只对index.html有效
// 浏览器刷新时,index.html页面自动携带Cache-Control: max-age=0
// 相当于响应头中的Cache-Control: no-cache
Cache-Control: max-age=0
// 允许缓存;即时过期,进入协商缓存阶段
其他值测试都无效果
2. 响应头字段(Response Header)
对于静态资源请求,服务器会自动携带Cache-Control: public, max-age=0
对于ajax请求,默认没有Cache-Control字段,需要手动设置
/** Express启动的应用,html, js,css文件默认返回的值;**/
Cache-Control: public,max-age=0
// public: 表示服务器允许客户端,CDN等代理服务器等缓存
// max-age: 允许缓存,并且缓存过期时间是0,下次请求就会进入协商缓存;
Cache-Control: private
// 只允许客户端缓存
这个值和请求头中的行为不一致
Cache-Control: no-cache
// 允许缓存,立即过期,直接进入协商缓存;
Cache-Control: no-store
// 不允许缓存资源;相当于请求头中的no-cache
index.html无效;它即使在过期时间内,也直接执行协商缓存;
// js文件有效。再次访问,在缓存过期时间内,直接从内存中获取,状态码200(from memory cache),不会向服务器发起请求;过期后进入协商缓存阶段
Cache-Control: max-age=5 // 5秒
// 允许缓存,并且过期时间距离响应返回时间5秒;5秒内直接从缓存中取值,5秒后请求进入协商缓存
2. 缓存协商策略
协商策略是在本身有缓存,但是缓存过期后的请求规则。
对于静态资源资源请求,服务器会自动添加对应的字段。
1. http1.0协商缓存字段
1. Last-Modified(响应头)/If-Modified-Since(请求头)
只能精确到秒,精确度比较低
Last-Modified: Tue, 04 Apr 2017 10:01:15 GMT // GMT时间格式;只能精确到秒
If-Modified-Since: Tue, 04 Apr 2017 10:01:15 GMT // GMT时间格式
1)如果某接口初次加载的时候允许缓存,客户端会将响应头和返回的内容进行缓存。再次请求的时候去缓存区根据缓存的响应头max-age/Expires判断,缓存是否过期;
2)如果没有过期,直接从缓存获取内容,不再向服务器发送请求,对应的状态码200(from memory cache/from dish cache);
3)如果已经过期, 从缓存的响应头中取出Last-Modified的值,赋值给请求头的If-Modified-Since,发起请求,在服务器端将If-Modified-Since的值和被请求资源的Last-Modified比较。
如果相同,则说明资源没有修改,返回304,然后浏览器去缓存区获取内容。如果不同,说明资源已经修改,服务器返回200, 返回最新的资源,更新响应头,并更新缓存区内容。
2. Etag(响应头)/If-None-Match(请求头)
优先级高于Last-Modified,如果共存,会先判断Etag。
ETag会读取文件内容,使用md5摘要算法,返回一个hash值。它不适合体积较大的文件,否则会出现性能问题。。
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4" //唯一标识符号
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
ETag: W/"0815" // W/表示弱验证
If-None-Match: W/"0815"
1)同上面第一步,先判断是否过期。
2)如果没有过期,从缓存区返回数据,响应状态码为200(from memory cache/from dish cache)。
3)如果过期,从缓存区响应头取出Etag的值,赋值给请求头If-None-Match字段,向服务器发起请求。在服务器端将If-None-Match和被请求资源的Etag比较。
如果相同,说明资源未改变,服务器返回304,浏览器去缓存区获取资源;如果不同,说明资源修改,返回200,同时更新响应头,返回最新的资源,并更新缓存区内容。
3. 强制更新/废弃缓存内容
强制不适用缓存资源。
1. 问题描述:
用户从收藏夹点击进入网站,浏览器加载的index.html文件始终是旧文件。
解决办法:
在服务器端,设置返回index.html文件的响应的时候,响应头设置Cache-Control: no-store不允许缓存或者Cache-Control: max-age=0/no-cache只允许协商缓存。
2. 问题描述:
如果资源文件(js/css等)设置的缓存过期时间特别久,则浏览器会一直从本地缓存资源获取文件,不向服务器发出请求。一直获取不到最新的文件。
解决办法:
1)修改引入文件的文件名(添加hash后缀)
将js/css文件添加hash后缀。对于浏览器来说,文件后缀修改,对于浏览器来说是新的资源,会重新加载资源。
2)给引入文件路由添加时间戳
url+?timeStamp=1323123213, 浏览器也会认为是新的资源