博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
深入node.js-浏览器缓存机制
阅读量:7237 次
发布时间:2019-06-29

本文共 4832 字,大约阅读时间需要 16 分钟。

浏览器缓存

浏览器缓存(Browser Caching)是为了节约网络的资源加速浏览,浏览器在用户磁盘上对最近请求过的文档进行存储,当访问者再次请求这个页面时,浏览器就可以从本地磁盘显示文档,这样就可以加速页面的阅览。

浏览器缓存的使用是提高用户体验的一个重要途径,通常也是优化前端的一种重要方式。利用好了缓存可以加快页面的浏览,降低服务器的压力,减少网络损耗等功能。图片描述

浏览器缓存分类

  • 协商缓存
  • 强制缓存

协商缓存

通过上图分析:

  • 客户端向服务器请求资源
  • 验证标识,如果标识通过了验证,则会响应304,告知浏览器读取缓存
  • 如果没有标识,或验证没有通过,则返回请求的资源

看到这里可能有人会有问题,标识是什么?

标识主要是用来标识请求的资源是否被修改或更新过,通过请求头发送给服务器进行验证。

协商缓存的标识有两种:

  • ETag
  • Last-Modified

下面我们来讲讲这两者的区别以及用法

Last-Modified

last-modified 根据词义就可以知道表示该资源的最后修改时间。

  • 客户端第一次请求服务器,服务器会把该资源的最后修改时间通过响应头返回给客户端
  • 客户端再次请求服务器的时候,如果在响应头中有Last-Modified字段,浏览器就会在请求头中加上if-Modified-Since字段给服务器。
  • 服务器拿到该字段的值,与该资源的最后修改时间进行对比,如果相等则说明资源没有被修改,向客户端返回304。
  • 浏览器看到304就会去读取缓存信息并呈现。

下面根据以上的几个点,来看看代码怎么实现:

const http = require('http');    const url = require('url');    const path = require('path');    const fs = require('fs');    const mime = require('mime');        const server = http.createServer((req, res) => {      // 获取文件名      const { pathname } = url.parse(req.url, true);      // 获取文件路径      const filepath = path.join(__dirname, pathname);          /**       * 判断文件是否存在       */      fs.stat(filepath, (err, stat) => {        if (err) {          res.end('not found');        } else {          // 获取if-modified-since这个请求头          const ifModifiedSince = req.headers['if-modified-since'];          // 获取资源最后修改时间          let lastModified = stat.ctime.toGMTString();          // 验证资源是否被修改过,如果相同则返回304让浏览器读取缓存          if (ifModifiedSince === lastModified) {            res.writeHead(304);            res.end();          }          // 缓存没有通过则返回资源,并加上 last-modified响应头,下次浏览器就会在请求头中带着 if-modified-since          else {            res.setHeader('Content-Type', mime.getType(filepath));            res.setHeader('Last-Modified', stat.ctime.toGMTString());            fs.createReadStream(filepath).pipe(res);          }        }      });    });        server.listen(8000, () => {      console.log('listen to 8000 port');    });

ETag

  • ETag它的流程和last-modified是一样的,仅仅只是验证方式不同,last-modified是取的当前请求资源的最后修改时间来作为验证,而ETag则是对当前请求的资源做一个唯一的标识。
  • 标识可以是一个字符串,文件的size,hash等等,只要能够合理标识资源的唯一性并能验证是否修改过就可以了。比如读取文件内容,将文件内容转换成一个hash值,每次接收到客户端发送过来的时候,重新读取文件转成hash值,与之前的做对比,看资源是否修改过。
  • 和Last-Modify相同,服务器在响应头返回一个ETag字段,那么请求的时候就会在请求头中加入if-none-match

下面来看看代码,代码中我都会加入详细的注释:

const http = require('http');const url = require('url');const path = require('path');const fs = require('fs');const mime = require('mime');const crypto = require('crypto');const server = http.createServer(function(req, res) {  // 获取请求的资源名称  let { pathname } = url.parse(req.url, true);  // 获取文件路径  let filepath = path.join(__dirname, pathname);  /**   * 判断文件是否存在   */  fs.stat(filepath, (err, stat) => {    if (err) {      return sendError(req, res);    } else {      let ifNoneMatch = req.headers['if-none-match'];      let readStream = fs.createReadStream(filepath);      let md5 = crypto.createHash('md5');      // 通过流的方式读取文件并且通过md5进行加密,相当于转成一个hash字符串作为etag的值      readStream.on('data', function(data) {        md5.update(data);      });      readStream.on('end', function() {        let etag = md5.digest('hex');        // 验证etag,判断资源是否被修改过,如果没有则返回304        if (ifNoneMatch === etag) {          res.writeHead(304);          res.end();        } 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('listen to 8000 port');});

强制缓存

图片描述

通过上图分析:

  • 强制缓存通过Cache-Control这个响应头中的max-age:60(缓存60s)来判断缓存是否过期
  • 如果过期了则重新向服务器请求资源
  • 如果没有过期,则不经过服务器,直接读取资源

强制缓存比较简单,直接看一下代码的实现

const http = require('http');    const url = require('url');    const path = require('path');    const fs = require('fs');    const mime = require('mime');        const server = http.createServer(function(req, res) {      let { pathname } = url.parse(req.url, true);      let filepath = 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 {          return send(req, res, filepath);        }      });    });    server.listen(8000, () => {      console.log('listen to port 8000');    });

强制缓存就是向浏览器设置一个过期时间例如cache-control:max-age=60表示这是一个60秒的过期时间,60秒以内浏览器都会从缓存读取该资源,超过60秒则访问服务器

cache-control还有另外几个值可以设置

  • private 客户端可以缓存
  • public 客户端和代理服务器都可以缓存
  • max-age=60 缓存内容将在60秒后失效
  • no-cache 需要使用对比缓存验证数据,强制向源服务器再次验证
  • no-store 所有内容都不会缓存,强制缓存和对比缓存都不会触发

总结

理解缓存对前端开发来说十分的重要,这也是为何把这篇文章写出来的原因,后续会继续为大家带来node相关的文章,如果写错或不好的地方希望大家指出来,如果觉得写的还行,麻烦点个赞哈!

以下我的新个人微信公众号,也会为大家持续提供原创文章,欢迎大家关注,如果用户量足够,会在里面为大家提供一些项目类的视频教程,谢谢

图片描述

转载地址:http://wtgfm.baihongyu.com/

你可能感兴趣的文章
EnterpriseFrameWork框架基础功能之字典数据配置管理
查看>>
今年,全球产业互联网发展提速
查看>>
漂浮式水上光伏场址如何选择?
查看>>
CloudCC CRM观点:移动应用已成必然
查看>>
我谈软件测试
查看>>
一波未平,一波又起:“永恒之石”恶意程序利用七种NSA“网络武器”
查看>>
远程数据中心蓬勃发展
查看>>
《Effective Debugging:软件和系统调试的66个有效方法》——第14条:考虑对软件进行更新...
查看>>
面部识别是把双刃剑 取长补短是要诀
查看>>
百亿新能源发电补贴是庞氏骗局?
查看>>
DTS
查看>>
福建省政府召开常务会议 确定出台加快物联网产业发展的八条措施
查看>>
Vantage公司在圣克拉拉建设其第4个数据中心
查看>>
《Linux从入门到精通(第2版)》——1.2 Linux系统发展史和优势
查看>>
安全的发布 .NET 应用的改动到产品服务器环境
查看>>
多种负载均衡算法及其 Java 代码实现
查看>>
《IP多播网络的设计与部署(第1卷)》——2.4 多播转发
查看>>
《Photoshop修色圣典(第5版)》—第1章1.3节色适应和同时对比
查看>>
《Adobe Illustrator CS5中文版经典教程》—第0课0.17节使用透视
查看>>
Linux 爆新漏洞,长按回车 70 秒可获得 root 权限
查看>>