本文展示是基于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. C++ STL标准模板库(list)

    //list的使用 #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<list> using namesp ...

  2. EJB的优点有哪些?(选择2项)

    EJB的优点有哪些?(选择2项) A.技术领先 B.价格低廉 C.性能优越 D.强大的容器支持 解答:CD

  3. The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Cha

    The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Cha ...

  4. 卡友pos机使用流程

    Q: pos机正常使用步骤 A: 1. 按开机键开机2. 输入“01”进行签到3. 系统提示输入密码,密码为“0000”4. 系统提示“请刷卡”,可正常刷卡消费首次使用请务必登陆商户后台核对结算收款账 ...

  5. VC++ Debug格式化数值显示

    When you watch variables in the Watch or Quick Watch window, the values are displayed using the defa ...

  6. 【BZOJ4631】踩气球 链表+线段树+堆

    [BZOJ4631]踩气球 Description 六一儿童节到了, SHUXK 被迫陪着M个熊孩子玩一个无聊的游戏:有N个盒子从左到右排成一排,第i个盒子里装着Ai个气球. SHUXK 要进行Q次操 ...

  7. mysql数据库导入到oracle数据库

    首先,写一个cmd脚本 xx.cmd sqlldr username/password control=xx.ctl errors=10000000 direct=y 再写一个bat脚本xx.bat ...

  8. Less-css预处理Node and VS扩展编译

    node编译 第一步:https://nodejs.org/en/  到node官网下载最新的node 第二步:和普通软件一样把node安装好 第三步:运行-cmd,准备安装less 全局安装(整个电 ...

  9. dev EditMask 设置方法

    官方帮助地址: https://documentation.devexpress.com/WindowsForms/583/Controls-and-Libraries/Editors-and-Sim ...

  10. Type Java compiler level does not match the version of the installed Java project facet.项目内容没错但是项目上报错,不影响运行

    1.Window->Show View->Problems 2.在项目上右键properties->project Facets->修改右侧的version  保持一致 3.w ...