Node.js静态文件服务器改进版

首先还是先感谢github,感谢github上提供此段源码的作者。跟昨晚的来比今天的静态文件服务器有点点复杂些,可以学到很多新的东西。

仔细会发现这次的代码多了一个fs.stat函数和ReadStream对象的pipe函数,stat这个函数是用来获取文件信息。第一个参数是传入文件路径,第二个则是回调函数,回调函数的第二个参数stats的属性文件的基本信息。pipe函数用于将这个可读流和destination目标可写流连接起来,传入这个流中的数据将会写入到destination流中。通过在必要时暂停和恢复流,来源流和目的流得以保持同步。

静态文件服务器的改进点在于使用了Last-Modified和If-Modified-Since报文头,可以不必要给浏览器返回它已经存在的文件。顺便可以根据浏览器请求资源的压缩方式返回给资源进行gzip或者deflate压缩。

rush:js;"> var PORT = 8000; var http = require("http"); var url = require("url"); var fs = require("fs"); var path = require("path"); var mime = require("./mime").types; var config = require("./config"); var zlib = require("zlib"); var server = http.createServer(function(request,response) { response.setHeader("Server","Node/V5"); var pathname = url.parse(request.url).pathname; console.log("url = " + pathname); if (pathname.slice(-1) === "/") { pathname = pathname + config.Welcome.file; } var realPath = __dirname + "/" + path.join("assets",path.normalize(pathname.replace(/\.\./g,""))); console.log("realPath = " + realPath); var pathHandle = function (realPath) { fs.stat(realPath,function (err,stats) { if (err) { response.writeHead(404,"Not Found",{'Content-Type': 'text/plain'}); response.write("stats = " + stats); response.write("This request URL " + pathname + " was not found on this server."); response.end(); } else { if (stats.isDirectory()) { realPath = path.join(realPath,"/",config.Welcome.file); pathHandle(realPath); } else { var ext = path.extname(realPath); ext = ext ? ext.slice(1) : 'unkNown'; var contentType = mime[ext] || "text/plain"; response.setHeader("Content-Type",contentType); //获得文件修改时间 var lastModified = stats.mtime.toUTCString(); var ifModifiedSince = "If-Modified-Since".toLowerCase(); //设置Last-Modified //服务器给浏览器返回文件最后一次修改时间Last-Modified response.setHeader("Last-Modified",lastModified);
 if (ext.match(con<a href="https://www.jb51.cc/tag/fig/" target="_blank" class="keywords">fig</a>.Expires.fileMatch)) {
  var expires = new Date();
  expires.setTime(expires.getTime() + con<a href="https://www.jb51.cc/tag/fig/" target="_blank" class="keywords">fig</a>.Expires.maxAge * 1000);
  response.setHeader("Expires",expires.toUTCString());
  response.setHeader("Cache-Control","max-age=" + con<a href="https://www.jb51.cc/tag/fig/" target="_blank" class="keywords">fig</a>.Expires.maxAge);
 }
 //服务器接收浏览器发送过来的If-Modified-Since报文头
 //日期相同表示该资源没有变化则返回304
 //告诉浏览器该资源你已经有了,不需要再请求了
 if (request.headers[ifModifiedSince] && lastModified == request.headers[ifModifiedSince]) {
  response.writeHead(304,"Not Modified");
  response.end();
 } else {
  var raw = fs.createReadStream(realPath);
  var acceptEncoding = request.headers['accept-encoding'] || "";
  var matched = ext.match(con<a href="https://www.jb51.cc/tag/fig/" target="_blank" class="keywords">fig</a>.Compress.match); 
  if (matched && acceptEncoding.match(/\bgzip\b/)) {
   response.writeHead(200,"Ok",{'<a href="https://www.jb51.cc/tag/contentencoding/" target="_blank" class="keywords">content-encoding</a>': 'gzip'});
   raw.pipe(zlib.createGzip()).pipe(response);
  } else if (matched && acceptEncoding.match(/\bdeflate\b/)) {
   response.writeHead(200,{'<a href="https://www.jb51.cc/tag/contentencoding/" target="_blank" class="keywords">content-encoding</a>': 'deflate'});
   raw.pipe(zlib.createDeflate()).pipe(response);
  } else {
   response.writeHead(200,"Ok");
   raw.pipe(response);
  }
 }
}

}
});
};

pathHandle(realPath);
});
server.listen(PORT);
console.log("Server runing at port: " + PORT + ".");

Expires字段声明了一个网页或URL地址不再被浏览器缓存的时间,一旦超过了这个时间,浏览器都应该联系原始服务器。这里设置失效时间为1年。

rush:js;"> exports.Expires = { fileMatch: /^(gif|png|jpg|js|css)$/ig,maxAge: 60*60*24*365 }; exports.Compress = { match: /css|js|html/ig }; exports.Welcome = { file: "index.html" };

枚举各种资源的类型,可根据扩展名设置Content-Type。

rush:js;"> exports.types = { "css": "text/css","gif": "image/gif","html": "text/html","ico": "image/x-icon","jpeg": "image/jpeg","jpg": "image/jpeg","js": "text/javascript","json": "application/json","pdf": "application/pdf","png": "image/png","svg": "image/svg+xml","swf": "application/x-shockwave-flash","tiff": "image/tiff","txt": "text/plain","wav": "audio/x-wav","wma": "audio/x-ms-wma","wmv": "video/x-ms-wmv","xml": "text/xml" };

相关文章

前言 做过web项目开发的人对layer弹层组件肯定不陌生,作为l...
前言 前端表单校验是过滤无效数据、假数据、有毒数据的第一步...
前言 图片上传是web项目常见的需求,我基于之前的博客的代码...
前言 导出Excel文件这个功能,通常都是在后端实现返回前端一...
前言 众所周知,js是单线程的,从上往下,从左往右依次执行,...
前言 项目开发中,我们可能会碰到这样的需求:select标签,禁...