本文展示是基于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. css3学习笔记(一)

    1. IE下的渐变:  filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff',endColorstr='# ...

  2. Matlab之合并音频

    程序功能: 1.读入wav下的所有音频 2.每个音频截取前0.6秒 3.合并每个音频 clear all; cd = 'wav'; waveFiles = dir(fullfile(cd,'*.wav ...

  3. 数据挖据之GeoHash核心原理解析

    引子 机机是个好动又好学的孩子,平日里就喜欢拿着手机地图点点按按来查询一些好玩的东西.某一天机机到北海公园游玩,肚肚饿了,于是乎打开手机地图,搜索北海公园附近的餐馆,并选了其中一家用餐. 饭饱之后机机 ...

  4. 【BZOJ】2060: [Usaco2010 Nov]Visiting Cows 拜访奶牛(树形dp)

    http://www.lydsy.com/JudgeOnline/problem.php?id=2060 裸的树形dp d[x][1]表示访问x的数量,d[x][0]表示不访问x的数量 d[x][1] ...

  5. java collection 类图

    转载:http://visionsky.blog.51cto.com/733317/371809/

  6. 将socket5代理转换为http代理

    归根结底还是万恶的ZFW,MD弄得现在Google,gmail,dropbox都用不了了,看来这是要万民欢迎大中华局域网的到来了.最近在使用一同学的Shadowsocks来突破GFW的限制,可是电脑o ...

  7. Chem 3D模型的参数值更改方法

    在化学绘图软件ChemOffice 15.1中有个专门用于绘制三维结构的组件,就是Chem 3D.通过这个组件用户可以绘制3D模型并可以通过这个组件来计算一些化学数据.在使用Chem 3D组件过程中, ...

  8. 170214、mybatis一级和二级缓存

    mybatis一级缓存是指在内存中开辟一块区域,用来保存用户对数据库的操作信息(sql)和数据库返回的数据,如果下一次用户再执行相同的请求, 那么直接从内存中读数数据而不是从数据库读取. 其中数据的生 ...

  9. 用RSS订阅微信公众号

    现在用RSS的人应该不多了,不过还是写一下吧. 一.付费服务:今天看啥 1.付费原因: 目前,网上几乎没有免费的用RSS订阅微信公号的方法,所以我推荐的是付费方法: 具体使用的服务是今天看啥,服务还是 ...

  10. 把 hhkb 压在mac pro上面用

    不知道你们有没有这种感觉, 用惯了外接键盘,然后切换到笔记本自带键盘的时候 手指会有不适应感? 直接 hhkb 放2018款的mac pro上总会压着原来的键盘, 而且我也不想直接禁用掉笔记本自带的键 ...