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 相关文章推荐
延时重复执行函数 lLoopRun.js
May 08 Javascript
jQuery Ajax异步处理Json数据详解
Nov 05 Javascript
jQuery实现单击按钮遮罩弹出对话框(仿天猫的删除对话框)
Apr 10 Javascript
Bootstrap3学习笔记(二)之排版
May 20 Javascript
JS匹配日期和时间的正则表达式示例
May 12 Javascript
JavaScript之排序函数_动力节点Java学院整理
Jun 30 Javascript
JavaScript编写的网页小游戏,很给力
Aug 18 Javascript
jQuery实现表单动态添加数据并提交的方法
Jul 19 jQuery
vue 项目中使用Loading组件的示例代码
Aug 31 Javascript
ES6入门教程之Array.from()方法
Mar 23 Javascript
JS 事件机制完整示例分析
Jan 15 Javascript
vue props 单项数据流实例分享
Feb 16 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
ajax取消挂起请求的处理方法
2013/03/18 PHP
php启用zlib压缩文件的配置方法
2013/06/12 PHP
php使用百度翻译api示例分享
2014/01/31 PHP
php把数据表导出为Excel表的最简单、最快的方法(不用插件)
2014/05/10 PHP
讲解WordPress开发中一些常用的debug技巧
2015/12/18 PHP
php常用字符函数实例小结
2016/12/29 PHP
总结PHP中初始化空数组的最佳方法
2019/02/13 PHP
js获取单选按钮的数据
2006/11/27 Javascript
javascript 检测浏览器类型和版本的代码
2009/09/15 Javascript
Javascript学习笔记2 函数
2010/01/11 Javascript
Bootstrap3制作搜索框样式的方法
2016/07/11 Javascript
JS高仿抛物线加入购物车特效实现代码
2017/02/20 Javascript
在node.js中怎么屏蔽掉favicon.ico的请求
2017/03/01 Javascript
纯js仿淘宝京东商品放大镜功能
2017/03/02 Javascript
vue通过watch对input做字数限定的方法
2017/07/13 Javascript
nodejs 生成和导出 word的实例代码
2018/07/31 NodeJs
VueJS 组件参数名命名与组件属性转化问题
2018/12/03 Javascript
简述vue-cli中chainWebpack的使用方法
2019/07/30 Javascript
微信小程序新闻网站详情页实例代码
2020/01/10 Javascript
vue实现分页的三种效果
2020/06/23 Javascript
python自定义解析简单xml格式文件的方法
2015/05/11 Python
Python Property属性的2种用法
2015/06/21 Python
给你选择Python语言实现机器学习算法的三大理由
2017/11/15 Python
Python get获取页面cookie代码实例
2018/09/12 Python
浅谈Python3识别判断图片主要颜色并和颜色库进行对比的方法
2019/10/25 Python
python类中super() 的使用解析
2019/12/19 Python
探秘TensorFlow 和 NumPy 的 Broadcasting 机制
2020/03/13 Python
Python第三方库的几种安装方式(小结)
2020/04/03 Python
英国最大的线上保健品零售商之一:Vitamin Planet
2016/12/01 全球购物
彪马西班牙官网:PUMA西班牙
2019/06/18 全球购物
CAD制图人员的自荐信
2014/02/07 职场文书
人口与计划生育目标管理责任书
2014/07/29 职场文书
群众路线领导班子整改方案
2014/10/25 职场文书
订货会邀请函
2015/01/31 职场文书
2015年助残日活动总结
2015/03/27 职场文书
幼儿园体操比赛口号
2015/12/25 职场文书