node.js实现http服务器与浏览器之间的内容缓存操作示例

本文实例讲述了node.js实现http服务器与浏览器之间的内容缓存操作。分享给大家供大家参考,具体如下:

一、缓存的作用

1、减少了数据传输,节约流量。

2、减少服务器压力,提高服务器性能。

3、加快客户端加载页面的速度。

二、缓存的分类

1、强制缓存,如果缓存有效,则不需要与服务器发生交互,直接使用缓存。

2、对比缓存,每次都需要与服务器发生交互,对缓存进行比较判断是否可以使用缓存。

三、通过使用 Last-Modified / If-Modified-Since 来进行缓存判断

1、Last-Modified 是服务器向客户端发送的头信息,用于告诉客户端资源的 最后修改时间,该信息浏览器会保存起来。

2、If-Modified-Since 是客户端向服务器发送的头信息,当客户端再次请求资源时,浏览器会带上该信息发送给服务器,服务器通过该信息来判断资源是否过期。

3、如果没有过期,则响应 304 表示 未更新,告诉浏览器使用保存的缓存。

4、如果过期了,则响应 200,返回最新的资源。

const http = require('http');
const url = require('url');
const path = require('path');
const fs = require('fs');
const util = require('util');
const mime = require('mime');
//创建http服务器并监听端口
let server = http.createServer();
server.listen(1234, '0.0.0.0', function () {
  console.log('开始监听');
});
function sendFile(req, res, filePath, stats) {
  //设置文件内容类型
  res.setHeader('Content-Type', mime.getType(filePath));
  //设置资源最后修改时间头信息
  res.setHeader('Last-Modified', stats.ctime.toGMTString());
  //通过管道将文件数据发送给客户端
  fs.createReadStream(filePath).pipe(res);
}
server.on('request', function (req, res) {
  let {pathname} = url.parse(req.url, true);
  //获取文件真实路径
  let filePath = path.join(__dirname, pathname);
  //判断文件是否存在
  fs.stat(filePath, function (err, stats) {
    if (err) {
      return res.end(util.inspect(err));
    }
    if (!stats.isFile()) {
      return res.end('is not file');
    }
    //获取客户端请求的If-Modified-Since头信息
    let ifModifiedSince = req.headers['if-modified-since'];
    if (ifModifiedSince) {
      //如果最后修改时间相同,说明该资源并未修改,直接响应 304,让浏览器从缓存中获取数据。
      if (ifModifiedSince == stats.ctime.toGMTString()) {
        res.statusCode = 304;
        res.end();
      } else {
        sendFile(req, res, filePath, stats);
      }
    } else {
      sendFile(req, res, filePath, stats);
    }
  });
});

通过最后修改时间判断缓存是否可用,并不是很精确,有如下几个问题:

1、Last-Modified 只精确到秒,秒以下的时间修改,将无法准确判断。

2、文件最后修改时间变了,但 内容并没有发生改变。

3、文件存在于多个 CDN 上,那该文件的最后修改时间是不一样的。

四、通过 ETag / If-None-Match 进行判断

ETag 表示 实体标签,将内容通过 hash 算法生成一段字符串,用以标识资源,如果资源发生变化,则 ETag 也会变化。

ETag 是服务器生成的,发送给客户端的。

1、客户端请求资源,服务器根据资源生成ETag,发送给客户端。浏览器会保存该信息。

2、当客户端再次请求时,浏览器会发送 If-None-Match 给服务器,值为第1步保存的信息,服务器通过该信息进行判断,资源是否修改过。

3、如果没有修改过,则响应 304 未更新,告诉浏览器使用保存的缓存。

4、如果修改过,则响应 200,返回最新资源。

const http = require('http');
const url = require('url');
const path = require('path');
const fs = require('fs');
const util = require('util');
const crypto = require('crypto');
const mime = require('mime');
//创建http服务器并监听端口
let server = http.createServer();
server.listen(1234, '0.0.0.0', function () {
  console.log('开始监听');
});
function sendFile(req, res, filePath, eTag) {
  //设置文件内容类型
  res.setHeader('Content-Type', mime.getType(filePath));
  //设置ETag头信息
  res.setHeader('ETag', eTag);
  //通过管道将文件数据发送给客户端
  fs.createReadStream(filePath).pipe(res);
}
server.on('request', function (req, res) {
  let {pathname} = url.parse(req.url, true);
  //获取文件真实路径
  let filePath = path.join(__dirname, pathname);
  //判断文件是否存在
  fs.stat(filePath, function (err, stats) {
    if (err) {
      return res.end(util.inspect(err));
    }
    if (!stats.isFile()) {
      return res.end('is not file');
    }
    //获取客户端请求的If-None-Match头信息
    let ifNoneMatch = req.headers['if-none-match'];
    //创建可读流
    let rs = fs.createReadStream(filePath);
    //创建md5算法
    let md5 = crypto.createHash('md5');
    rs.on('data', function (data) {
      md5.update(data);
    });
    rs.on('end', function () {
      let eTag = md5.digest('hex');
      if (ifNoneMatch) {
        //判断eTag与客户端发送过来的If-None-Match是否相等
        if (ifNoneMatch == eTag) {
          res.statusCode = 304;
          res.end();
        } else {
          sendFile(req, res, filePath, eTag);
        }
      } else {
        sendFile(req, res, filePath, eTag);
      }
    });
  });
});

五、让浏览器在缓存有效期内不用发请求

Expires 是http1.0的内容,用于设置缓存的有效期,在有效期内浏览器直接从浏览器缓存中获取数据。

Cache-Control 与Expires作用一样,是http1.1的内容,用于指明当前资源的有效期,优先级高于Expires。

Cache-Control可以设置的值 :

1、private 客户端可以缓存

2、public  客户端和代理服务器都可以缓存

3、max-age=10 缓存内容在10秒后失效

4、no-cache 使用对比缓存验证,强制向服务器验证

5、no-store 内容都不缓存,强制缓存和对比缓存都不会触发

const http = require('http');
const url = require('url');
const path = require('path');
const fs = require('fs');
const util = require('util');
const mime = require('mime');
//创建http服务器并监听端口
let server = http.createServer();
server.listen(1234, '0.0.0.0', function () {
  console.log('开始监听');
});
function sendFile(req, res, filePath, stats) {
  //设置文件内容类型
  res.setHeader('Content-Type', mime.getType(filePath));
  //设置缓存失效时间60秒
  res.setHeader('Expires', new Date(Date.now() + 60 * 1000).toUTCString());
  //设置缓存失效时间60秒
  res.setHeader('Cache-Control', 'max-age=60');
  //通过管道将文件数据发送给客户端
  fs.createReadStream(filePath).pipe(res);
}
server.on('request', function (req, res) {
  let {pathname} = url.parse(req.url, true);
  //获取文件真实路径
  let filePath = path.join(__dirname, pathname);
  //判断文件是否存在
  fs.stat(filePath, function (err, stats) {
    if (err) {
      return res.end(util.inspect(err));
    }
    if (!stats.isFile()) {
      return res.end('is not file');
    }
    sendFile(req, res, filePath, stats)
  });
});

希望本文所述对大家node.js程序设计有所帮助。

(0)

相关推荐

  • Nodejs基于LRU算法实现的缓存处理操作示例

    本文实例讲述了Nodejs基于LRU算法实现的缓存处理操作.分享给大家供大家参考,具体如下: LRU是Least Recently Used的缩写,即最近最少使用页面置换算法,是为虚拟页式存储管理服务的,是根据页面调入内存后的使用情况进行决策了.由于无法预测各页面将来的使用情况,只能利用"最近的过去"作为"最近的将来"的近似,因此,LRU算法就是将最近最久未使用的页面予以淘汰. 可以用一个特殊的栈来保存当前正在使用的各个页面的页面号.当一个新的进程访问某页面时,便将

  • Nodejs下DNS缓存问题浅析

    无意间看到一个文章,是关于nodejs下发送http请求不会缓存dns结果的.这意味着,如果你基于nodejs写了一个http采集程序,不提供dns缓存则会让每次请求都傻傻的重复解析域名为ip地址.听起来会非常影响性能不是么? 我的项目中,发送http请求并不是使用的node原生的http库,而是依赖一个常用的Request库.我查阅了一下该库的相关文档和github issue,也发现了一些和dns相关的帖子.不过多数说的是,关于dns问题,本身并不是Request库的范畴,而归结于nodej

  • nodejs读取图片返回给浏览器显示

    本文主要是使用nodejs处理图片等资源返回给浏览器显示方法,但不只限制于图片,也可以是音频视频等其他非字符串文件的返回和显示.也可以扩展成nodejs静态资源服务器的开发方法. 请求头说明 在http响应里面有几个重要的东西,Content-Type 说明文件渲染MIME类型,这是我们本文的相关处理关键. 常用的MIME类型 { "css": "text/css", "gif": "image/gif", "htm

  • node.js使用 http-proxy 创建代理服务器操作示例

    本文实例讲述了node.js使用 http-proxy 创建代理服务器操作.分享给大家供大家参考,具体如下: 代理,也称网络代理,是一种特殊网络服务,允许一个终端通过代理服务与另一个终端进行非直接的连接,这样利于安全和防止被攻击. 代理服务器,就是代理网络用户去获取网络信息,就是信息的中转,负责转发. 代理又分 正向代理 和 反向代理: 正向代理:帮助局域网内的用户访问外面的服务. 反向代理:帮助外面的用户访问局域网内部的服务. 一.安装 http-proxy npm install http-

  • nodejs使用redis作为缓存介质实现的封装缓存类示例

    本文实例讲述了nodejs使用redis作为缓存介质实现的封装缓存类.分享给大家供大家参考,具体如下: 之前在node下使用redis作为缓存介质,对redis进行了一层封装 First: 安装npm包 redis const redis = require('redis'); Second: 进行封装 // cache.js const redis = require('redis'); const config = require('config'); const logger = requ

  • Node.js 实现简单的无侵入式缓存框架的方法

    前言 python 的flask.ext.cache 通过注解这样对方法返回结果进行缓存: @cache.cached(timeout=300, key_prefix='view_%s', unless=None) def hello(name=None): print 'view hello called' return render_template('hello.html', name=name) 这类实现方式对业务逻辑没有丝毫的侵入性,非常之优雅. 最近在做 Node.js 地项目,然而

  • node Buffer缓存区常见操作示例

    本文实例讲述了node Buffer缓存区常见操作.分享给大家供大家参考,具体如下: 创建buffer类 var buf=new buffer(10); var buf=new buffer([10,20,30,40]); var buf=new buffer("www.baidu.com","utf-8"); 写入缓存区 buf.write(string[,offset[,length]][encoding]) buf=new buffer(256); len=b

  • Node.js中使用Log.io在浏览器中实时监控日志(等同tail -f命令)

    今天,抽空了浏览了下node.js ,哈哈,看了一篇入门的文章(http://www.nodebeginner.org/index-zh-cn.html),自我感觉是入门了,不过里面一句话,挺有感悟: 复制代码 代码如下: 不过,这些毕竟都是前端技术,尽管当想要增强页面的时候,使用jQuery总让你觉得很爽,但到最后,你顶多是个JavaScript用户,而非JavaScript开发者.然后,出现了Node.js,服务端的JavaScript,这有多酷啊?于是,你觉得是时候该重新拾起既熟悉又陌生的

  • javascript常用方法、属性集合及NodeList 和 HTMLCollection 的浏览器差异

    在您开始本文的阅读前,我强烈建议您可以先读一读此篇:http://w3help.org/zh-cn/causes/SD9004.            HTMLCollection 接口定义 interface HTMLCollection{      readonly attribute unsigned long   length;      Node               item(in unsigned long index);      Node               na

  • node.js使用http模块创建服务器和客户端完整示例

    本文实例讲述了node.js使用http模块创建服务器和客户端.分享给大家供大家参考,具体如下: node.js中的 http 模块提供了创建服务器和客户端的方法,http 全称是超文本传输协议,基于 tcp 之上,属于应用层协议. 一.创建http服务器 const http = require('http'); //创建一个http服务器 let server = http.createServer(); //监听端口 server.listen(8888, '0.0.0.0'); //设置

  • node.js利用redis数据库缓存数据的方法

    一.运行redis Redis服务器默认使用6379端口 redis-server 自定义端口 redis-server –port 6390 客户端 redis-cli 指定ip和端口连接 redis-cli -h 127.0.0.1 -p 6390 测试客户端和服务器是否连通 ping 二.Nodejs连接redis 通过redis.createClient(port,host,options)来连接redis服务器 var redis = require("redis") var

随机推荐