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


Posted in Javascript onJanuary 10, 2016

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

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

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

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(config.Expires.fileMatch)) {
      var expires = new Date();
      expires.setTime(expires.getTime() + config.Expires.maxAge * 1000);
      response.setHeader("Expires", expires.toUTCString());
      response.setHeader("Cache-Control", "max-age=" + config.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(config.Compress.match); 
      if (matched && acceptEncoding.match(/\bgzip\b/)) {
       response.writeHead(200, "Ok", {'Content-Encoding': 'gzip'});
       raw.pipe(zlib.createGzip()).pipe(response);
      } else if (matched && acceptEncoding.match(/\bdeflate\b/)) {
       response.writeHead(200, "Ok", {'Content-Encoding': '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年。

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。

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"
};
Javascript 相关文章推荐
Js 获取当前日期时间及其它操作实现代码
Mar 04 Javascript
parseInt parseFloat js字符串转换数字
Aug 01 Javascript
七个很有意思的PHP函数
May 12 Javascript
高性能JavaScript模板引擎实现原理详解
Feb 05 Javascript
jQuery仅用3行代码实现的显示与隐藏功能完整实例
Oct 08 Javascript
Vue过滤器的用法和自定义过滤器使用
Feb 08 Javascript
超全面的javascript中变量命名规则
Feb 09 Javascript
微信小程序实现搜索指定景点周边美食、酒店
May 18 Javascript
vue.js实现只能输入数字的输入框
Oct 19 Javascript
vue页面切换项目实现转场动画的方法
Nov 12 Javascript
Vue 实现简易多行滚动"弹幕"效果
Jan 02 Javascript
一文读懂vue动态属性数据绑定(v-bind指令)
Jul 20 Javascript
实例讲解javascript注册事件处理函数
Jan 09 #Javascript
详解javascript事件冒泡
Jan 09 #Javascript
js父页面中使用子页面的方法
Jan 09 #Javascript
jquery调整表格行tr上下顺序实例讲解
Jan 09 #Javascript
实例讲解js验证表单项是否为空的方法
Jan 09 #Javascript
小心!AngularJS结合RequireJS做文件合并压缩的那些坑
Jan 09 #Javascript
javascript跑马灯抽奖实例讲解
Apr 17 #Javascript
You might like
[FAQ]PHP中的一些常识:类篇
2006/10/09 PHP
php安装xdebug/php安装pear/phpunit详解步骤(图)
2013/12/22 PHP
一个简单的PHP验证码实现代码
2014/05/10 PHP
使用Js让Html中特殊字符不被转义
2013/11/05 Javascript
js实现的折叠导航示例
2013/11/29 Javascript
javascript中的循环语句for语句深入理解
2014/04/04 Javascript
JavaScript中输出信息的方法(信息确认框-提示输入框-文档流输出)
2016/06/12 Javascript
数组Array的一些方法(总结)
2017/02/17 Javascript
浅谈ajax请求不同页面的微信JSSDK问题
2018/02/26 Javascript
iview table render集成switch开关的实例
2018/03/14 Javascript
微信小程序多音频播放进度条问题
2018/08/28 Javascript
基于Nodejs的Tcp封包和解包的理解
2018/09/19 NodeJs
node实现mock-plugin中间件的方法
2019/12/25 Javascript
解决Vue router-link绑定事件不生效的问题
2020/07/22 Javascript
解决vue 使用axios.all()方法发起多个请求控制台报错的问题
2020/11/09 Javascript
vue常用高阶函数及综合实例
2021/02/25 Vue.js
详解Python中的__new__、__init__、__call__三个特殊方法
2016/06/02 Python
python编程实现12306的一个小爬虫实例
2017/12/27 Python
Python中文编码知识点
2019/02/18 Python
Python使用lambda表达式对字典排序操作示例
2019/07/25 Python
浅谈Pytorch中的torch.gather函数的含义
2019/08/18 Python
python和JavaScript哪个容易上手
2020/06/23 Python
浅谈python 类方法/静态方法
2020/09/18 Python
python 简单的调用有道翻译
2020/11/25 Python
CSS3动画特效在活动页中的应用
2020/01/21 HTML / CSS
介绍一下SQL注入攻击的种类和防范手段
2012/02/18 面试题
大学应届生求职简历的自我评价
2013/10/08 职场文书
外企求职信范文分享
2013/12/31 职场文书
网络程序员自荐信
2014/01/25 职场文书
论文评语大全
2014/04/29 职场文书
村党支部换届选举方案
2014/05/02 职场文书
社区助残日活动总结
2014/08/29 职场文书
高中生期中考试失利检讨书
2014/10/23 职场文书
新闻稿怎么写
2015/07/18 职场文书
学生会部长竞选稿
2015/11/19 职场文书
检举信的写法
2019/04/10 职场文书