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_03_javascript全局观
Oct 11 Javascript
js实现新浪微博首页效果
Oct 16 Javascript
require.js 加载 vue组件 r.js 合并压缩的实例
Oct 14 Javascript
文件上传插件SWFUpload的使用指南
Nov 29 Javascript
从零学习node.js之利用express搭建简易论坛(七)
Feb 25 Javascript
使用canvas进行图像编辑的实例
Aug 29 Javascript
jQuery实现的简单无刷新评论功能示例
Nov 08 jQuery
浅谈vue引用静态资源需要注意的事项
Sep 28 Javascript
jQuery实现购物车的总价计算和总价传值功能
Nov 28 jQuery
浅谈Vue3.0之前你必须知道的TypeScript实战技巧
Sep 11 Javascript
基于Angular 8和Bootstrap 4实现动态主题切换的示例代码
Feb 11 Javascript
JavaScript实现动态生成表格
Aug 02 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验证手机号码(支持归属地查询及编码为UTF8)
2013/02/01 PHP
php自动加载方式集合
2016/04/04 PHP
PHP自定义图片缩放函数实现等比例不失真缩放的方法
2016/08/19 PHP
centos下file_put_contents()无法写入文件的原因及解决方法
2017/04/01 PHP
PHP与Perl之间知识点区别整理
2019/03/19 PHP
PHP数组Key强制类型转换实现原理解析
2020/09/01 PHP
JQuery jsonp 使用示例代码
2009/08/12 Javascript
学习ExtJS(二) Button常用方法
2009/10/07 Javascript
JQuery与iframe交互实现代码
2009/12/24 Javascript
toString()一个会自动调用的方法
2010/02/08 Javascript
五段实用的js高级技巧
2011/12/20 Javascript
jQuery实现点击标题输入详细信息
2013/04/16 Javascript
JS实现弹性漂浮效果的广告代码
2015/09/02 Javascript
基于jQuery封装的分页组件
2017/06/26 jQuery
对layui中表单元素的使用详解
2018/08/15 Javascript
JS函数内部属性之arguments和this实例解析
2018/10/07 Javascript
JsonProperty 的使用方法详解
2019/10/11 Javascript
js HTML DOM EventListener功能与用法实例分析
2020/04/27 Javascript
谈谈node.js中的模块系统
2020/09/01 Javascript
[01:52]DOTA2完美大师赛Vega战队趣味视频——kpii老师小课堂
2017/11/25 DOTA
[01:47]2018年度DOTA2最佳教练-完美盛典
2018/12/16 DOTA
python遍历序列enumerate函数浅析
2017/10/17 Python
python虚拟环境迁移方法
2019/01/03 Python
使用python opencv对目录下图片进行去重的方法
2019/01/12 Python
使用Python paramiko模块利用多线程实现ssh并发执行操作
2019/12/05 Python
Python timeit模块的使用实践
2020/01/13 Python
tensorflow生成多个tfrecord文件实例
2020/02/17 Python
Pycharm IDE的安装和使用教程详解
2020/04/30 Python
Nginx+Uwsgi+Django 项目部署到服务器的思路详解
2020/05/08 Python
使用CSS禁止textarea调整大小功能的方法
2015/03/13 HTML / CSS
CSS3+js实现简单的时钟特效
2015/03/18 HTML / CSS
基于HTML5超酷摄像头(HTML5 webcam)拍照功能实现代码
2012/12/13 HTML / CSS
全球异乡人的跨境社交电商平台:Kouhigh口嗨网
2020/07/24 全球购物
2015年药店店长工作总结
2015/04/29 职场文书
golang中切片copy复制和等号复制的区别介绍
2021/04/27 Golang