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 相关文章推荐
javascript hasFocus使用实例
Jun 29 Javascript
详细介绍8款超实用JavaScript框架
Oct 25 Javascript
JS点击链接后慢慢展开隐藏着图片的方法
Feb 17 Javascript
Node.js的项目构建工具Grunt的安装与配置教程
May 12 Javascript
轻松实现js选项卡切换效果
Sep 24 Javascript
微信小程序 实战小程序实例
Oct 08 Javascript
给easyui datebox扩展一个清空的实例
Nov 09 Javascript
windows下vue-cli及webpack搭建安装环境
Apr 25 Javascript
使用3D引擎threeJS实现星空粒子移动效果
Sep 13 Javascript
mui js控制开关状态、修改switch开关的值方法
Sep 03 Javascript
jQuery实现简单飞机大战
Jul 05 jQuery
Vue-cli4 配置 element-ui 按需引入操作
Sep 11 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安装攻略:常见问题解答(一)
2006/10/09 PHP
php编程中echo用逗号和用点号连接的区别
2016/03/26 PHP
ThinkPHP连接Oracle数据库
2016/04/22 PHP
js 新浪的一个图片播放图片轮换效果代码
2008/07/15 Javascript
javascript使用switch case实现动态改变超级链接文字及地址
2014/12/16 Javascript
jQuery中:first选择器用法实例
2014/12/30 Javascript
jQuery提示插件alertify使用指南
2015/04/21 Javascript
分享9点个人认为比较重要的javascript 编程技巧
2015/04/27 Javascript
JavaScript学习笔记整理之引用类型
2016/01/22 Javascript
jQuery中的一些常见方法小结(推荐)
2016/06/13 Javascript
Vue.js结合bootstrap实现分页控件
2017/03/10 Javascript
浅谈Angular 中何时取消订阅
2017/11/22 Javascript
分析JavaScript数组操作难点
2017/12/18 Javascript
Vue 实现手动刷新组件的方法
2019/02/19 Javascript
微信小程序组件传值图示过程详解
2019/07/31 Javascript
微信小程序实现签字功能
2019/12/23 Javascript
Python+微信接口实现运维报警
2016/08/27 Python
Python中二维列表如何获取子区域元素的组成
2017/01/19 Python
Python2与python3中 for 循环语句基础与实例分析
2017/11/20 Python
python使用tcp实现局域网内文件传输
2020/03/20 Python
Python中应该使用%还是format来格式化字符串
2018/09/25 Python
python语言基本语句用法总结
2019/06/11 Python
在Django中实现添加user到group并查看
2019/11/18 Python
tensorflow安装成功import tensorflow 出现问题
2020/04/16 Python
英国骑行、跑步、游泳、铁人三项运动装备专卖店:Wiggle
2016/08/23 全球购物
ASOS英国官网:英国在线时装和化妆品零售商
2017/05/19 全球购物
女子锻炼服装和瑜伽服装:Splits59
2019/03/04 全球购物
物业门卫岗位职责
2013/12/28 职场文书
代理协议书
2014/04/22 职场文书
2014年人事科工作总结
2014/11/19 职场文书
闪闪的红星观后感
2015/06/08 职场文书
网吧管理制度范本
2015/08/05 职场文书
导游词之太原天龙山
2020/01/02 职场文书
教你使用TensorFlow2识别验证码
2021/06/11 Python
mysql分表之后如何平滑上线详解
2021/11/01 MySQL
redis复制有可能碰到的问题汇总
2022/04/03 Redis