本文展示是基于node.js的静态文件服务器,代码参考自这里,主要是练习node http、文件模块的使用,另外,对理解http协议也很有帮助
除了实现了基本的路由控制,还实现了MIME类型、304缓存、gzip压缩、目录读取

首先是配置文件,setting.js

var setting = {
webroot : '/xxx/xxx/webroot',
viewdir : false,
index : 'index.html', //只有当viewdir为false时,此设置才有用
expires : {
filematch : /^(gif|png|jpg|js|css)$/ig,
maxAge: 60 * 60 //默认为一个月
},
compress : {
match : /css|js|html/ig
}
};
module.exports = setting;

MIME映射,mime.js

var mime = {
"html": "text/html",
"ico": "image/x-icon",
"css": "text/css",
"gif": "image/gif",
"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"
};
module.exports = mime;

然后是主程序,server.js

var http = require('http');
var setting = require('./setting.js');
var mime = require('./mime');
var url = require('url');
var util = require('util');
var path = require('path');
var fs = require('fs');
var zlib = require('zlib');
//访问统计
var number = 0;
var accesses = {};
 
http.createServer(function(req, res){
res.number = ++number;
accesses[res.number] = {startTime : new Date().getTime()};
var pathname = url.parse(req.url).pathname;
//安全问题,禁止父路径
pathname = pathname.replace(/\.\./g, '');
var realPath = setting.webroot + pathname;
accesses[res.number].path = pathname;
readPath(req, res, realPath, pathname);
}).listen(8000);
 
console.log('http server start at parth 8000\n\n\n');
//判断文件是否存在
function readPath(req, res, realPath, pathname){
//首先判断所请求的资源是否存在
path.exists(realPath, function(ex){
console.log('path.exists--%s', ex);
if(!ex){
responseWrite(res, 404, {'Content-Type' : 'text/plain'},
'This request URL ' + pathname + ' was not found on this server.');
}else{
//文件类型
fs.stat(realPath, function(err, stat){
if(err){
responseWrite(res, 500, err);
}else{
//目录
if(stat.isDirectory()){
//是否读取目录
if(setting.viewdir){
fs.readdir(realPath, function(err, files){
if(err){
responseWrite(res, 500, err);
}else{
var htm = '<html><head><title>' + pathname + '</title></head><body>' + pathname + '<hr>';
for(var i = 0; i < files.length; i++){
htm += '<br><a href="' + pathname + (pathname.slice(-1) != '/' ? '/' : '')
+ files[i] + '">' + files[i] + '</a>', 'utf8';
}
responseWrite(res, 200, {'Content-Type' : 'text/html'}, htm);
}
});
}else if(setting.index && realPath.indexOf(setting.index) < 0){
readPath(req, res, path.join(realPath, '/', setting.index), path.join(pathname, '/', setting.index));
}else{
responseWrite(res, 404, {'Content-Type' : 'text/plain'},
'This request URL ' + pathname + ' was not found on this server.');
}
}else{
var type = path.extname(realPath);
type = type ? type.slice(1) : 'nuknown';
var header = {'Content-Type' : mime[type] || 'text/plain'};
//缓存支持
if(setting.expires && setting.expires.filematch
&& type.match(setting.expires.filematch)){
var expires = new Date(),
maxAge = setting.expires.maxAge || 3600 * 30;
expires.setTime(expires.getTime() + maxAge * 1000);
header['Expires'] = expires.toUTCString();
header['Cache-Control'] = 'max-age=' + maxAge;
var lastModified = stat.mtime.toUTCString();
header['Last-Modified'] = lastModified;
//判断是否304
if(req.headers['if-modified-since'] && lastModified == req.headers['if-modified-since']){
responseWrite(res, 304, 'Not Modified');
}else{
readFile(req, res, realPath, header, type);
}
}else{
readFile(req, res, realPath, header, type);
}
}
}
});
}
});
}
//读文件/压缩/输出
function readFile(req, res, realPath, header, type){
var raw = fs.createReadStream(realPath), cFun;
//是否gzip
if(setting.compress && setting.compress.match
&& type.match(setting.compress.match) && req.headers['accept-encoding']){
if(req.headers['accept-encoding'].match(/\bgzip\b/)){
header['Content-Encoding'] = 'gzip';
cFun = 'createGzip';
}else if(req.headers['accept-encoding'].match(/\bdeflate\b/)){
header['Content-Encoding'] = 'deflate';
cFun = 'createDeflate';
}
}
res.writeHead(200, header);
if(cFun){
raw.pipe(zlib[cFun]()).pipe(res);
}else{
raw.pipe(res);
}
}
//普通输出
function responseWrite(res, starus, header, output, encoding){
encoding = encoding || 'utf8';
res.writeHead(starus, header);
if(output){
res.write(output, encoding);
}
res.end();
accesses[res.number].endTime = new Date().getTime();
//日志输出
console.log('access[%s]--%s--%s--%s--%s\n\n', res.number, accesses[res.number].path,
(accesses[res.number].endTime - accesses[res.number].startTime),
starus, (output ? output.length : 0));
delete accesses[res.number];
}

over!
尚欠缺的功能:日志记录、断点、容错等~~以后有时间再加啦

nodejs入门-静态文件服务器的更多相关文章

  1. 从零开始,在windows上用nodejs搭建一个静态文件服务器

    从零开始,在windows上用nodejs搭建一个静态文件服务器 首先安装nodejs: 新建一个node文件夹 下载node.exe到该文件夹 下载npm然后解压到该文件夹 现在node文件夹是这样 ...

  2. [转载]用NodeJS打造你的静态文件服务器

    http://www.open-open.com/bbs/view/1321344823593 本文是我对V5Node项目的总结,该项目的特性包括: 项目大多数的文件都是属于静态文件,只有数据部分存在 ...

  3. 转:nginx入门指南,快速搭建静态文件服务器和代理服务器

    本文介绍 Nginx 入门基础知识,让你迅速搭建 Nginx 服务器.主要内容包括 Nginx 安装和简单使用.Nginx的简单原理.Nginx 配置文件的结构.如何使用 Nginx 来提供静态文件服 ...

  4. 我的前端之旅-nodejs 安装静态的文件服务器 (1)

    一个最简单的 Web Server 之功能包含下列三个步骤:步骤一 : 接收浏览器所传来的网址:步骤二 : 取出相对应的文件:步骤三 : 将文件内容传回给浏览器.然而.在这个接收与传回的过程中,所有的 ...

  5. Node.js静态文件服务器实战[转]

    p.s. 在下面这篇文章的指导下,做了一个静态文件服务器,见:https://github.com/walkerwzy/node_static_server ==== 这是一篇阐述得比较详细的文章,从 ...

  6. Anywhere 随启随用的静态文件服务器

    三江建材官网项目 写nodeJs系列的文章都是因为这一个项目 第一天,搭建项目环境 记录心情: 首先,在写这个项目的时候,我很无助,只是拿到了设计稿,还有一个指导人,平常会很忙,只有在休闲的时候才能动 ...

  7. nodeJs 5.0.0 安装配置与nodeJs入门例子学习

    新手学习笔记,高手请自动略过 安装可以先看这篇:http://blog.csdn.net/bushizhuanjia/article/details/7915017 1.首先到官网去下载exe,或者m ...

  8. NodeJS入门(四)—— path对象

    很快Node就会迎来4.0的时代,届时将并入现有的iojs,所以先前写过的iojs入门系列直接更名为NodeJS入门. 本篇开始将逐个介绍Node的各主要模块,依循API文档走一遍,但会给出比API文 ...

  9. nodejs express 静态文件的路径

    当express 设置为静态文件服务器的时候.可以通过2种方式进行方位: 1,通过设置app.use('路径1','../a/b/image') express 路径的形式,如 src="路 ...

随机推荐

  1. python笔记2-数据类型:元组、字典常用操作

    元组 Python的元组与列表类似,不同之处在于元组的元素不能修改. 元组使用小括号,列表使用方括号. 元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可. tp=(1,2,3,'a','b' ...

  2. NDK版本 下载地址

    最新版本r16 https://dl.google.com/android/repository/android-ndk-r16-windows-x86.zip https://dl.google.c ...

  3. 【ARDUINO】蓝牙(HC-05)透传

    1.蓝牙连接ARDUINO 工作模式:VCC-5.5V GND-GND TXD-RX RXD-TX  工作模式下默认波特率38400 AT模式,在工作模式的基础上KEY-VCC/5.5V 设置从模式: ...

  4. Hadoop2的FN安装(federated namespace)

    尝试了简单的安装hadoop2后,我们再来尝试一下hdfs的一项新功能:FN.这项技术可以解决namenode容量不足的问题.它采用多个namenode来共享datanode的方式,每个namenod ...

  5. Java逍遥游记读书笔记<三>

    异常处理 如何判断一个方法中可能抛出异常 该方法中出现throw语句 该方法调用了其他已经带throws子句的方法. 如果方法中可能抛出异常,有两种处理方法: 1.若当前方法有能力处理异常,则用Try ...

  6. MathType可以编辑带圈乘号吗

    在数学中有很多符号,可能这些符号我们用得上,也有些符号我们很少用,甚至用不上,但是我们用不上,不代表不存在这个符号,也不代表别人用不上,只是各自所涉及到的知识领域不一样而已.而对于加减乘除运算,几乎每 ...

  7. iOS开发:iPhone6、6 plus适配

    本文转载至 http://jingyan.baidu.com/article/8cdccae97a5c2b315413cda9.html 1 2 3 4 5 6 7 分步阅读 随着苹果公司持续推出新产 ...

  8. 【BZOJ4688】One-Dimensional 矩阵乘法

    [BZOJ4688]One-Dimensional Description 考虑一个含有 N 个细胞的一维细胞自动机.细胞从 0 到 N-1 标号.每个细胞有一个被表示成一个小于 M 的非负整数的状态 ...

  9. Blue Bird

    Blue Bird 哈巴他一 他拉 毛套拉那 一套一太(他)卖咋西他 闹哇 啊哦一 啊哦一 啊闹扫啦 卡那西米哇马达 哦包爱 啦来字赛次那撒哇姨妈 次卡米哈几卖他阿娜塔爱套一大 靠闹看叫毛姨妈靠逃吧你 ...

  10. iOS侧面加shadow

    UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRect:_bgView.bounds]; _bgView.layer.masksToBo ...