找回密码
 会员注册
查看: 28|回复: 0

HTTP缓存之强缓存和协商缓存

[复制链接]

2万

主题

0

回帖

6万

积分

超级版主

积分
64425
发表于 2024-9-19 16:28:27 | 显示全部楼层 |阅读模式
http缓存:Web缓存是可以自动保存常见文档副本的HTTP设备。当Web请求抵达缓存时,如果本地有“已缓存的”副本,就可以从本地存储设备而不是原始服务器中提取这个文档。使用缓存主要有如下几个优点:缓存减少了冗余的数据传输,节省了你的网络费用。缓存缓解了网络瓶颈问题。不需要更多的带宽就能够更快的加载页面。缓存降低了对原始服务器的要求。服务器可以更快地响应,避免过载的出现。缓存降低了距离时延,因为从较远的地方加载页面会更慢一些。缓存的处理步骤:一个缓存从接收到请求到做出响应,大概可以分为如下7个步骤:接收——缓存从网络中读取抵达的请求报文。解析——缓存对报文进行解析,提取出URL和各种首部。查询——缓存查看是否有本地副本可用,如果没有,就获取一份副本(并将其保存在本地)。新鲜度检测——缓存查看已缓存副本是否足够新鲜,如果不是,就询问服务器是否有任何更新。创建响应——缓存会用新的首部和已缓存的主体来构建一条响应报文。发送——缓存通过网络将响应发回给客户端。日志——缓存可选地创建一个日志文件条目来描述这个事务。Http缓存流程图:状态码区别:200请求成功,服务器返回全新的数据200frommemorycache/fromdiskcache本地强缓存还在有效期,直接使用本地缓存304请求成功,走了协商缓存,服务器判定(Etag和Last-modified)没有过期,告知浏览器使用缓存业务中的使用场景:项目中,我们主要使用缓存来存储html、css、js、img等静态资源,一般不会去存储动态资源,因为对动态资源的缓存会对数据实时性造成影响1、强制缓存强缓存是当我们访问URL的时候,不会向服务器发送请求,直接从缓存中读取资源,但是会返回200的状态码。我们第一次进入页面,请求服务器,然后服务器进行应答,浏览器会根据responseHeader来判断是否对资源进行缓存,如果响应头中expires、pragma或者cache-control字段,代表这是强缓存,浏览器就会把资源缓存在memorycache或diskcache中。第二次请求时,浏览器判断请求参数,如果符合强缓存条件就直接返回状态码200,从本地缓存中拿数据。否则把响应参数存在requestheader请求头中,看是否符合协商缓存,符合则返回状态码304,不符合则服务器会返回全新资源。Expires:这是http1.0时的规范;它的值为一个绝对时间的GMT格式的时间字符串,如Mon,10Jun202221:31:12GMT,如果发送请求的时间在expires之前,那么本地缓存始终有效,否则就会发送请求到服务器来获取资源。Expires过度依赖本地时间,如果本地与服务器时间不同步,就会出现资源无法被缓存或者资源永远被缓存的情况。所以,Expires字段几乎不被使用了cache-control:上面我们提到了Expires有个缺点,当客户端本地时间和服务器时间不一致时会产生误差,浏览器会直接向服务器请求新的资源,为了解决这个问题,在http1.1规范中,提出了cache-control字段,且这个字段优先级高于上面提到的Expires,值是相对时间。在cache-control中有常见的几个响应属性值,它们分别是:max-age=100 缓存100秒后过期,资源缓存在本地s-maxage 覆盖max-age,作用与max-age一样,但只用于代理服务器中缓存no-cache 不使用本地缓存。使用协商缓存,先与服务器确认返回的响应是否被更改,如果之前的响应中存在ETag,那么请求的时候会与服务端验证,如果资源未被更改,则可以避免重新下载。no-store 所有内容都不会被缓存,既不使用强制缓存也不适用协商缓存,每次用户请求该资源,都会向服务器发送一个请求,服务器再返回资源public 可以被所有的用户缓存,包括客户端和代理服务器private 只能被客户端缓存,不允许CDN等中继缓存服务器对其缓存2、协商缓存上面提到的强缓存都是由本地浏览器在确定是否使用缓存,当浏览器没有命中强缓存时就会向浏览器发送请求,验证协商缓存是否命中,如果缓存命中则返回304状态码,否则返回新的资源数据。协商缓存(也叫对比缓存)是由服务器来确定资源是否可用,这将涉及到两组字段成对出现的,在浏览器第一次发出请求时会带上字段(Last-Modified或者Etag),则后续请求则会带上对于的请求字段(if-modified-since或者if-none-Match),若响应头没有Last-Modified或者Etag,则请求头也不会有对应的字段基于Last-Modified:首先需要在服务器端读出文件修改时间,将读出来的修改时间赋给响应头的last-modified字段。最后设置Cache-control:no-cacheconsthttp=require('http');constfs=require('fs');http.createServer((req,res)=>{ if(req.url==='test.png'){ constdata=fs.readFileSync('./test.png'); const{mtime}=fs.statSync('./test.png'); consttemp=req.headers['if-modified-since']; if(temp===mtime.toUTCString()){ res.statusCode=304; res.end(); return; } res.setHeader('last-modified',mtime.toUTCString()); res.setHeader('Catch-Control','no=cache'); res.end(data); }else{ res.end(fs.readFileSync('./test.html')); }})基于ETag:第一次请求某资源的时候,服务端读取文件并计算出文件指纹,将文件指纹放在响应头的etag字段中跟资源一起返回给客户端。第二次请求某资源的时候,客户端自动从缓存中读取出上一次服务端返回的ETag也就是文件指纹。并赋给请求头的if-None-Match字段,让上一次的文件指纹跟随请求一起回到服务端。服务端拿到请求头中的is-None-Match字段值(也就是上一次的文件指纹),并再次读取目标资源并生成文件指纹,两个指纹做对比。如果两个文件指纹完全吻合,说明文件没有被改变,则直接返回304状态码和一个空的响应体并return。如果两个文件指纹不吻合,则说明文件被更改,那么将新的文件指纹重新存储到响应头的ETag中并返回给客户端consthttp=require('http');constfs=require('fs');constetag=require('etag');http.createServer((req,res)=>{ if(req.url==='test.png'){ constdata=fs.readFileSync('./test.png'); constetagContent=etag(data); constnoMatch=req.headers['if-none-match']; if(noMatch===etagContent){ res.statusCode=304; res.end(); return; } res.setHeader('etag',etagContent); res.setHeader('Catch-Control','no=cache'); res.end(data); }else{ res.end(fs.readFileSync('./test.html')); }})作者简介毕清华:精选主力干将!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-26 23:24 , Processed in 0.376126 second(s), 26 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表