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 相关文章推荐
Prototype使用指南之selector.js
Jan 10 Javascript
jquery 文本上下无缝滚动,鼠标放上去就停止 小例子
Jun 05 Javascript
IE6下javasc#ipt:void(0) 无效的解决方法
Dec 23 Javascript
jQuery过滤选择器详解
Jan 13 Javascript
jQuery实现新消息在网页标题闪烁提示
Jun 23 Javascript
基于javascript实现tab切换特效
Mar 29 Javascript
详谈jQuery unbind 删除绑定事件 / 移除标签方法
Mar 02 Javascript
微信小程序获取循环元素id以及wx.login登录操作
Aug 17 Javascript
利用babel将es6语法转es5的简单示例
Dec 01 Javascript
解决循环中setTimeout执行顺序的问题
Jun 20 Javascript
浅谈在不使用ssr的情况下解决Vue单页面SEO问题(2)
Nov 08 Javascript
解决包含在label标签下的checkbox在ie8及以下版本点击事件无效果兼容的问题
Oct 27 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
PHP 正则表达式常用函数
2014/08/17 PHP
php短网址和数字之间相互转换的方法
2015/03/13 PHP
phpStudy访问速度慢和启动失败的解决办法
2015/11/19 PHP
php自定义函数实现JS的escape的方法示例
2016/07/07 PHP
通过修改Laravel Auth使用salt和password进行认证用户详解
2017/08/17 PHP
PHP设计模式之策略模式原理与用法实例分析
2019/04/04 PHP
使用jquery解析XML的方法
2014/09/05 Javascript
JavaScript运行机制之事件循环(Event Loop)详解
2014/10/10 Javascript
简单掌握JavaScript中const声明常量与变量的用法
2016/05/21 Javascript
深入理解JS函数的参数(arguments)的使用
2016/05/28 Javascript
js实现当鼠标移到表格上时显示这一格全部内容的代码
2016/06/12 Javascript
jquery.tableSort.js表格排序插件使用方法详解
2020/08/12 Javascript
你有必要知道的10个JavaScript难点
2017/07/25 Javascript
JS与HTML结合实现流程进度展示条思路详解
2017/09/03 Javascript
解决vue中对象属性改变视图不更新的问题
2018/02/23 Javascript
JavaScript实现构造json数组的方法分析
2018/08/17 Javascript
详解JS实现简单的时分秒倒计时代码
2019/04/25 Javascript
详解vue 自定义组件使用v-model 及探究其中原理
2019/10/11 Javascript
vue element 关闭当前tab 跳转到上一路由操作
2020/07/22 Javascript
[01:37]TI4西雅图DOTA2前线报道 VG拿下首胜教练357给出获胜秘诀
2014/07/10 DOTA
Python内置的字符串处理函数整理
2013/01/29 Python
Python中使用md5sum检查目录中相同文件代码分享
2015/02/02 Python
python2.7的编码问题与解决方法
2016/10/04 Python
python利用matplotlib库绘制饼图的方法示例
2016/12/18 Python
python分治法求二维数组局部峰值方法
2018/04/03 Python
python基于物品协同过滤算法实现代码
2018/05/31 Python
对Python w和w+权限的区别详解
2019/01/23 Python
python控制nao机器人身体动作实例详解
2019/04/29 Python
python实现将文件夹内的每张图片批量分割成多张
2019/07/22 Python
Python 异常的捕获、异常的传递与主动抛出异常操作示例
2019/09/23 Python
TFRecord文件查看包含的所有Features代码
2020/02/17 Python
python3.6.8 + pycharm + PyQt5 环境搭建的图文教程
2020/06/11 Python
酒店保安员岗位职责
2014/01/31 职场文书
优质服务演讲稿
2014/05/14 职场文书
2016年度继续教育学习心得体会
2016/01/19 职场文书
Feign调用传输文件异常的解决
2021/06/24 Java/Android