本文实例讲述了node.js实现http服务器与浏览器之间的内容缓存操作。分享给大家供大家参考,具体如下:一、缓存的作用一、缓存的作用1、减少了数据传输,节约流量。2、减少服务器压力,提高服务器性能。3、加快客户端加载页面的速度。二、缓存的分类二、缓存的分类1、强制缓存,如果缓存有效,则不需要与服务器发生交互,直接使用缓存。2、对比缓存,每次都需要与服务器发生交互,对缓存进行比较判断是否可以使用缓存。三、通过使用 Last-Modified / If-Modified-Since 来进行缓存判断三、通过使用 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);

}

});
});


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 / 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);

}

});

});
});


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)

});
});


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程序设计有所帮助。