node~ http缓存

缓存

  • 减少了冗余的数据传输,节省了贷款。
  • 减少了服务器的负担, 大大提高了网站的性能
  • 加快了客户端加载网页的速度

Chrome://cache

缓存分强制缓存和对比缓存

强制缓存如果生效,不需要再和服务器发生交互,而对比缓存不管是否生效,都需要与服务端发生交互,强制缓存优先级高于对比缓存

强制缓存 (第一次访问走服务器,在一段时间内走缓存)

//Expires 过期时间,设置都是绝对时间 http,1.0 //Cache-Control http:1.1

<body>
    <img src='/favicon.ico' alt="">
</body>
复制代码
//服务器
let http = require('http');
let url = require('url');
let path = require('path');
let fs = require('fs');
let zlib = require('zlib');
let mime = require('mime'); // mime可以根据路径判断当前文件是什么类型 npm install mime
let server = http.createServer(function (req,res) {
    let {pathname} = url.parse(req.url,true);
    if(pathname === '/' || pathname === '\\') pathname = '\index.html';
    //如果访问的是localhost:3000/ 会访问c盘
    let p = path.join(__dirname,pathname); //判断路径是否存在
    fs.stat(p,function (err,stat) {
        if(!err){
            let d = new Date(Date.now()+5000).toUTCString();//科学时间
            res.setHeader('Expires', d); // http1.0  哪天哪秒要过期 默认1.0
            res.setHeader('Cache-Control', 'max-age=5') // http1.1  最大存活时间 单位是秒
            res.setHeader('Content-Type', mime.getType(p) + ';charset=utf8');//mime根据当前文件名判断文件类型,mime需要安装
            fs.createReadStream(p).pipe(res);
        }else{
            res.statusCode = 404;
            res.end();
        }
    })
})
server.listen(3000);
复制代码

对比缓存 (每次请求的时候对比)

第一次来的时候给一个标识,下一次再来会带上这个标识,然后通过标识进行对比,根据修改时间判断

//if-modified-since | last-modified

let http = require('http');
let url = require('url');
let path = require('path');
let fs = require('fs');
let zlib = require('zlib');
let mime = require('mime'); // mime可以根据路径判断当前文件是什么类型 npm install mime
let server = http.createServer(function (req,res) {
    let {pathname} = url.parse(req.url,true);
    if(pathname === '/' || pathname === '\\') pathname = '\index.html';
    let p = path.join(__dirname,pathname);
    fs.stat(p,function (err,stat) {
        if(!err){
            //对比缓存,看是否修改过,最后的修改时间
            if (req.headers['if-modified-since'] === stat.ctime.toUTCString()){
                res.statusCode = 304;
                res.end();
            }else{
                // 第一次设置Last-Modified 下一次请求时 会提供一个头 if-modified-since
                res.setHeader('Last-Modified', stat.ctime.toUTCString());//stat.ctime.toUTCString()当前时间
                res.setHeader('Cache-Control','no-cache');//关掉浏览器默认缓存机制
                fs.createReadStream(p).pipe(res);
            }
        }else{
            res.statusCode = 304;
            res.end();
        }
    })
})
server.listen(3000);
复制代码

参考: ctime 修改文件属性和修改内容都会改变 if-modified-since的时间并不准确,比如我们使用cdn发送到服务器的时间不同,我们可以对比内容,但是这样就会大大消耗性能

内容缓存对比

//etag实体标签,将文件读出来传过来,一般会用MD5摘要 返回 if -none-match

md5摘要算法参考

let http = require('http');
let url = require('url');
let path = require('path');
let fs = require('fs');
let zlib = require('zlib');
let mime = require('mime'); // mime可以根据路径判断当前文件是什么类型 npm install mime
let crypto = require('crypto'); // 常见的加密模块

let server = http.createServer(function (req,res) {
    let {pathname} = url.parse(req.url,true);
    if(pathname === '/' || pathname === '\\') pathname = '\index.html';
    let p = path.join(__dirname,pathname);
    fs.stat(p,function (err,stat) {
        // 强制缓存 协商缓存 = 三种都用,强制缓存期间不会请求服务器了
        if(!err){
            let md5 = crypto.createHash('md5');
            let rs = fs.createReadStream(p,{highWaterMark:3});
            rs.on('data',function (data) {
                md5.update(data); // update可以调用多次 data是buffer
            });
            rs.on('end', function (data) {
                //拿最新请求的加密值和客户端去比较
                lqt r = md5.digest('hex');
                if(req.heasers['if-none-match'] === r){
                    res.statusCode = 304;
                    res.end();
                }else{
                    res.setHeader('Etag', r);
                    res.setHeader('Cache-Control','no-cache');
                    fs.createReadStream(p).pipe(res);
                }
            })
        }else{
            res.statusCode = 304;
            res.end();
        }
        //对比缓存,看是否修改过,最后的修改时间
    })
})
server.listen(3000);
复制代码

上个方法很消耗性能,我们一般三个结合用,MD5摘要一般不会真的读,可能会用ctime时间戳和文件大小来作为摘要

终极方案

  • 强制缓存 协商缓存 = 三种都用,强制缓存期间不会请求服务器了
let http = require('http');
let url = require('url');
let path = require('path');
let fs = require('fs');
let zlib = require('zlib');
let mime = require('mime'); 
let crypto = require('crypto');
let server = http.createServer(function (req, res) {
    let { pathname } = url.parse(req.url, true);
    let p = path.join(__dirname, pathname);
    fs.stat(p, function (err, stat) {
        if (!err) {
            //是否修改过
            if (req.headers['if-modified-since'] === stat.ctime.toUTCString()){
                res.statusCode = 304;
                res.end();
            }else{
                let rs = fs.createReadStream(p);
                let md5 = crypto.createHash('md5');
                rs.on('data',function (data) {
                    md5.update(data);
                });
                // 可以用文件的大小和修改时间搭配使用 强制缓存 协商缓存 = 三种都用
                rs.on('end',function () {
                    let value = md5.digest('hex');
                    let head = req.headers['if-none-match'];
                    if(head === value){
                        res.statusCode = 304;
                        res.end();
                    }else{
                        //过期时间
                        res.setHeader('Last-Modified', stat.ctime.toUTCString());
                        let d = new Date(Date.now()+5000).toUTCString();
                        res.setHeader('Expires', d); // http1.0
                        res.setHeader('Cache-Control', 'max-age=5') // http1.1
                        res.setHeader('Content-Type', mime.getType(p) + ';charset=utf8');
                        res.setHeader('Etag', value);
                        fs.createReadStream(p).pipe(res);
                    }
                })
            }
        } else {
            res.statusCode = 304;
            res.end();
        }
    })
});
server.listen(3000);
复制代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值