在前端开发中,性能一直都是被你们所重视的一点,然而判断一个网站的性能最直观的就是看网页打开的速度。其中提升网页反应速度的一个方式就是使用缓存。一个优秀的缓存策略能够缩短网页请求资源的距离,减小延迟,而且因为缓存文件能够重复利用,还能够减小带宽,下降网络负荷。前端
由此可知:git
一、强制缓存阶段:先在本地查找该资源,若是有发现该资源,并且该资源尚未过时,就使用这一个资源,彻底不会发送http请求到服务器github
二、协商缓存阶段:若是在本地缓存找到对应的资源,可是不知道该资源是否过时或者已通过期,则发一个http请求到服务器,而后服务器判断这个请求,若是请求的资源在服务器上没有改动过,则返回304,让浏览器使用本地找到的那个资源;web
三、启发式缓存阶段算法
四、缓存失败阶段:当服务器发现请求的资源已经修改过,或者这是一个新的请求(在原本没有找到资源),服务器则返回该资源的数据,而且返回200, 固然这个是指找到资源的状况下,若是服务器上没有这个资源,则返回404。浏览器
由上面能够知道强制缓存是直接使用本地的缓存,不发送http请求,那么判断它是否要进行强制缓存的标志是什么呢?缓存
Expires是HTTP/1.0控制网页缓存的字段,其值为服务器返回该请求结果缓存的到期时间(绝对时间),即再次发起该请求时,若是客户端的当前时间小于Expires的值时,直接使用缓存结果。服务器
缺点:由于是绝对时间,若是客户端与服务端的时间由于某些缘由(例如时区不一样;客户端和服务端有一方的时间不许确)发生偏差,强缓存可能直接失效。cookie
app.get('/1.jpg',function(req,res,next){
...
res.setHeader('Expires', new Date(Date.now() + 10 * 1000).toUTCString())
})
复制代码
在HTTP/1.1中,Cache-Control是最重要的规则,主要用于控制网页缓存,它有几个选项: 一、public : 全部的内容都被缓存(客户端和代理服务器均可缓存) 二、private : 全部的内容都被缓存(客户端缓存,cache-control的默认值) 三、no-cache: 客户端缓存,可是是否使用缓存得经过协商缓存来决定 四、no-store: 全部内容都不缓存,既不强制缓存,又不协商缓存 五、max-age=num(num的单位是秒) : 缓存内容在num秒后失效,num为相对时间网络
app.get('/2.jpg',function(req,res,next){
res.setHeader('Expires', new Date(Date.now() + 10 * 1000).toUTCString())
res.setHeader('Cache-Control', 'max-age=20')
...
})
复制代码
通过强缓存后,客户端再请求,若是缓存标志有效,则返回灰色200,数据从浏览器缓存中取出。 优先级:Cache-Control > expires
当缓存过时时间的字段一个都没有的时候,浏览器下次并不会直接进入协商阶段,而是先进入启发式缓存阶段,你能够经过关闭服务器,刷新页面来观察。 它根据响应头中2个时间字段 Date 和 Last-Modified 之间的时间差值,取其值的10%做为缓存时间周期。 也就是说,当存有 Last-Modified字段的时候,即便是断网,且强缓存都失效后,也有必定时间是直接读取缓存文件的。 etag是没有这个阶段的。
协商阶段就是当强缓存阶段失效的时候,http请求会携带缓存标志符向服务器发起请求,由服务器来决定是否使用缓存,浏览器根据返回到code码来决定是否从浏览器缓存中拿去数据。
Last-Modified是服务器响应请求时,返回该资源文件在服务器最后被修改的时间。 If-Modified-Since是再次请求该资源文件的时候,会带上上次请求中的Last-Modified时间,服务器经过对比Last-Modified / If-Modified-Since,返回200,则有更新,从服务器拉取数据,304则使用缓存文件
app.get('/3.jpg',function(req,res,next){
...
let ifModifiedSince = req.headers['if-modified-since']
let LastModified = stat.ctime.toGMTString()
if(!!ifModifiedSince && LastModified === ifModifiedSince){
res.statusCode = 304
res.end()
}
if(!ifModifiedSince || (!!ifModifiedSince && LastModified !== ifModifiedSince)){
res.setHeader('Last-Modified', LastModified)
}
...
})
})
复制代码
Etag是服务器响应请求时,返回当前资源文件的一个惟一标识(由服务器根据文件信息算法生成,相似hash) If-None-Match是客户端再次发起该请求时,携带上次请求返回的惟一标识Etag值,经过此字段值告诉服务器该资源上次请求返回的惟一标识值。服务器收到该请求后,发现该请求头中含有If-None-Match,则会根据If-None-Match的字段值与该资源在服务器的Etag值作对比,一致则返回304,表明资源无更新,继续使用缓存文件;不一致则从新返回资源文件,状态码为200
app.get('/4.jpg',function(req,res,next){
reponseHandle(req,res,(stat)=>{
let ifNoneMatch = req.headers['if-none-match']
let etag = .....
if(!ifNoneMatch || (!!ifNoneMatch && ifNoneMatch!== etag)){
res.setHeader('ETag', etag)
}
if(!!ifNoneMatch && ifNoneMatch === etag){
res.statusCode = 304
res.end()
}
})
})
复制代码
Etag / If-None-Match优先级高于Last-Modified / If-Modified-Since,同时存在则只有Etag / If-None-Match生效
因而可知,强制缓存优先于协商缓存进行,若强制缓存(Expires和Cache-Control)生效则直接使用缓存,若不生效则进行协商缓存(Last-Modified / If-Modified-Since和Etag / If-None-Match),协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么表明该请求的缓存失效,从新获取请求结果,再存入浏览器缓存中;生效则返回304,继续使用缓存
字段 | 说明 |
---|---|
pragma | http1.0,值为no-cache为禁用缓存 |
vary | 基于字段区分缓存版本(res header) |
Date | 发送响应报文的时间(启发式缓存、代理服务器缓存) |
Age | 文件存于服务器的时间 |
accept-encoding | 请求服务器返回的文件类型 |
referer | 发送请求的源域名 |
CDN缓存,也叫网关缓存、反向代理缓存。浏览器先向CDN网关发起WEB请求,网关服务器后面对应着一台或多台负载均衡源服务器,会根据它们的负载请求,动态地请求转发到合适的源服务器上。
CDN的优点:
由于几个历史缘由,app cache已经不推荐使用,从web标准移除了。缘由以下:
Service workers 本质上充当Web应用程序与浏览器之间的代理服务器,也能够在网络可用时做为浏览器和网络间的代理。它们旨在(除其余以外)使得可以建立有效的离线体验,拦截网络请求并基于网络是否可用以及更新的资源是否驻留在服务器上来采起适当的动做。他们还容许访问推送通知和后台同步API。
service worker的特色:
具体请移步
key | value |
---|---|
expires | Cookie失效时间(绝对时间)若不设置,浏览器关闭即删除 |
Max-Age | Cookie失效时间,相对时间,优先级高于expires |
path | 设置哪些路径带上cookie,通常默认为'/' |
Domain | 设置哪些域名带上cookie,通常为当前一级域名 |
Secure | 只在https下才能发送cookie |
HttpOnly | js脚本获取不到,且只能在http上才能发送cookie(防止xss) |
SameSite | 是否可能做为第三方 cookie(防止CSRF) |
相同点
不一样点
推荐一下本身的我的公众号:前端精读(每日定时推送一篇前端好文)