浏览器缓存浏览器缓存(BrowserCaching)是为了节省网络资源,加??快浏览速度。浏览器将最近请求的文档存储在用户的磁盘上。当访问者再次访问该页面时,浏览器可以显示本地磁盘中的文档,可以加快页面的浏览速度。使用浏览器缓存是提升用户体验的重要方式,通常也是前端优化的重要方式。利用好缓存可以加快页面浏览速度,减轻服务器压力,减少网络丢失等功能。浏览器缓存分类协商缓存强制缓存协商缓存通过上图分析:客户端向服务端请求资源验证标识。如果标识符通过验证,它会响应304,告诉浏览器读取缓存。如果没有标识符或验证失败,则返回请求的资源。这里可能有人会有疑问。标识符是什么?标识符主要用于标识请求的资源是否被修改或更新,通过请求头发送给服务器进行校验。协商缓存的标识符有两种:ETagLast-Modified下面说说两者的区别和用法Last-Modifiedlast-modified根据词义可以知道资源的最后修改时间。当客户端第一次请求服务器时,服务器会通过响应头向客户端返回资源的最后修改时间。当客户端再次请求服务器时,如果响应头中有Last-Modified字段,浏览器就会在服务器上添加if-Modified-Since字段。服务器获取该字段的值并将其与资源的最后修改时间进行比较。如果相等,说明资源没有被修改,返回304给客户端。当浏览器看到304时,它会读取缓存的信息并呈现出来。下面根据以上几点来看代码是如何实现的:consthttp=require('http');consturl=require('url');constpath=require('路径');constfs=require('fs');constmime=require('mime');constserver=http.createServer((req,res)=>{//获取文件名const{pathname}=url.parse(req.url,true);//获取文件路径constfilepath=path.join(__dirname,pathname);/***判断文件是否存在*/fs.stat(filepath,(err,stat)=>{if(err){res.end('notfound');}else{//获取requestheaderif-modified-sinceconstifModifiedSince=req.headers['if-modified-since'];//获取资源的最后修改时间letlastModified=stat.ctime.toGMTString();//验证资源是否已被修改,若相同,则返回304让浏览器读取缓存被返回,并添加last-modified响应头,下次浏览器会在请求头中携带if-modified-sinceelse{res.setHeader('Content-Type',mime.getType(filepath));res.setHeader('Last-Modified',stat.ctime.toGMTString());fs.createReadStream(文件路径).pipe(res);}}});});server.listen(8000,()=>{console.log('监听8000端口');});ETagETag和last-modified的过程是一样的,只是校验方式不同,last-modified是以当前请求资源的最后修改时间作为校验,而ETag是为当前请求的资源做一个唯一标识。标识符可以是字符串、文件的大小、hash等,只要合理就足以标识资源的唯一性,验证是否被修改过。比如读取文件内容,将文件内容转换成哈希值。每次客户端发送时,重新读取文件并转换成哈希值,与之前的进行比较,看资源是否被修改。和Last-Modify一样,服务端在响应头中返回一个ETag字段,然后请求时在请求头中加入if-none-match。让我们看一下代码。我会在代码中添加详细注释:consthttp=require('http');consturl=require('url');constpath=require('path');constfs=require('fs');constmime=require('mime');constcrypto=require('crypto');constserver=http.createServer(function(req,res){//获取请求的资源名称let{pathname}=url.parse(req.url,true);//获取文件路径letfilepath=path.join(__dirname,pathname);/***判断文件是否存在*/fs.stat(filepath,(err,stat)=>{if(err){returnsendError(req,res);}else{letifNoneMatch=req.headers['if-none-match'];letreadStream=fs.createReadStream(filepath);letmd5=crypto.createHash('md5');//通过stream读取文件,并通过md5加密,相当于转换一个散列字符串作为etag的值readStream.on('data',function(data){md5.update(data);});readStream.on('end',function(){letetag=md5.digest('hex');//验证etag判断资源是否被修改,如果没有则返回304if(ifNone匹配===etag){res.writeHead(304);重发();}else{res.setHeader('Content-Type',mime.getType(filepath));//服务端第一次返回时,会根据文件内容计算出一个标识符发送给客户端fs.readFile(filepath,(err,content)=>{//客户端看到etag后,它还会在客户端保存这个标识符,下次再次访问服务器时,发送给服务器res.setHeader('Etag',etag);fs.createReadStream(filepath).pipe(res);});}});}});});server.listen(8000,()=>{console.log('监听8000端口');});强制缓存通过上图分析:强制缓存是通过Cache-Control响应头中的max-age:60(缓存60s)来判断缓存是否过期。如果过期,则重新向服务器请求资源。如果还没有过期,不经过服务器直接读取资源比较简单。强制缓存比较简单。只看代码的实现consthttp=require('http');consturl=require('url');constpath=require('路径');constfs=require('fs');constmime=require('mime');constserver=http.createServer(function(req,res){let{pathname}=url.parse(req.url,true);letfilepath=path.join(__dirname,pathname);fs.stat(filepath,(err,stat)=>{if(err){res.setHeader('Content-Type',mime.getType(filepath));//设置缓存过期时间res.setHeader('Cache-Control','max-age=100');fs.createReadStream(filepath).pipe(res);}else{returnsend(req,res,filepath);}});});server.listen(8000,()=>{console.log('监听8000端口');});强制缓存就是给浏览器设置一个过期时间。例如cache-control:max-age=60表示这是一个60秒的过期时间,60秒浏览器会在60秒内从缓存中读取资源,60秒后访问服务器。cache-control还有其他几个值可以设置为private,客户端可以缓存public,客户端和代理服务器都可以缓存max-age=60,60后缓存的内容将无效no-cacheseconds需要使用比对缓存来校验数据,强制源服务器再次校验no-store所有内容都不会被缓存,强制缓存和比对缓存都不会触发总结理解缓存对于前端开发重要,这就是写这篇文章的原因,以后我会继续给大家带来node相关的文章。如果你写错了或不好的地方,希望你能指出来。如果觉得写的还可以,请点个赞。哈!以下是我新的个人微信公众号公众号,我会继续为大家提供原创文章。欢迎您关注。如果用户够多,我会给大家提供一些项目相关的视频教程。谢谢
