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,返回最新的资源。
consthttp=require('http');
consturl=require('url');
constpath=require('path');
constfs=require('fs');
constutil=require('util');
constmime=require('mime');
//创建http服务器并监听端口
letserver=http.createServer();
server.listen(1234,'0.0.0.0',function(){
console.log('开始监听');
});
functionsendFile(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);
//获取文件真实路径
letfilePath=path.join(__dirname,pathname);
//判断文件是否存在
fs.stat(filePath,function(err,stats){
if(err){
returnres.end(util.inspect(err));
}
if(!stats.isFile()){
returnres.end('isnotfile');
}
//获取客户端请求的If-Modified-Since头信息
letifModifiedSince=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,返回最新资源。
consthttp=require('http');
consturl=require('url');
constpath=require('path');
constfs=require('fs');
constutil=require('util');
constcrypto=require('crypto');
constmime=require('mime');
//创建http服务器并监听端口
letserver=http.createServer();
server.listen(1234,'0.0.0.0',function(){
console.log('开始监听');
});
functionsendFile(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);
//获取文件真实路径
letfilePath=path.join(__dirname,pathname);
//判断文件是否存在
fs.stat(filePath,function(err,stats){
if(err){
returnres.end(util.inspect(err));
}
if(!stats.isFile()){
returnres.end('isnotfile');
}
//获取客户端请求的If-None-Match头信息
letifNoneMatch=req.headers['if-none-match'];
//创建可读流
letrs=fs.createReadStream(filePath);
//创建md5算法
letmd5=crypto.createHash('md5');
rs.on('data',function(data){
md5.update(data);
});
rs.on('end',function(){
leteTag=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内容都不缓存,强制缓存和对比缓存都不会触发
consthttp=require('http');
consturl=require('url');
constpath=require('path');
constfs=require('fs');
constutil=require('util');
constmime=require('mime');
//创建http服务器并监听端口
letserver=http.createServer();
server.listen(1234,'0.0.0.0',function(){
console.log('开始监听');
});
functionsendFile(req,res,filePath,stats){
//设置文件内容类型
res.setHeader('Content-Type',mime.getType(filePath));
//设置缓存失效时间60秒
res.setHeader('Expires',newDate(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);
//获取文件真实路径
letfilePath=path.join(__dirname,pathname);
//判断文件是否存在
fs.stat(filePath,function(err,stats){
if(err){
returnres.end(util.inspect(err));
}
if(!stats.isFile()){
returnres.end('isnotfile');
}
sendFile(req,res,filePath,stats)
});
});
希望本文所述对大家node.js程序设计有所帮助。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。