用NodeJS搭建静态文件服务器

引言

之前用lamp和wamp搭建过网站,集成的软件套装对于建站十分方便。apache的autoindex功能我非常喜欢,有时候想要分享一些文件给同学,但是又懒得用U盘复制,传网盘或者发邮件速度又太慢,而且学生党对于大文件传输网费非常昂贵。此时,apache的文件托管功能就非常合适了。把需要分享的文件放入指定的文件夹,然后直接告诉同学:喂,你连上路由器,登陆这个网址:192.168.1.1/share,你自己下载就行!(装逼。。。)

不过apache的功能对于像我这样的三脚猫,有时候是非常崩溃的。有时候autoindex功能开启了也不能访问文件,有时候文件夹设置很是麻烦,有时候mac系统和windows系统还不一样。配置apache是非常痛苦的!最近学着node,所以就想用Node来简单实现一下静态服务功能。不过,鉴于是初学者(我发现看了朴灵的《深入浅出NodeJS》对学习写代码很有帮助),是为了功能而功能的,在代码质量上还是存在很大问题的,希望各位大佬不吝赐教,给出改进的意见,提高代码质量。下面是我探究的过程。

过程

需要的模块

这里用到模块http,path,url,fs,mime,art-template

探索过程

思路:

  1. 客户端发起请求
  2. 请求路径path,对应文件路径 ./public/path
  3. 判断路径是文件还是文件夹
  4. 如果是文件,则将文件发送给客户端
  5. 如果是文件夹,则列出所有文件和文件夹,附上链接

为了美观(虽然还是很丑),实现5采用的是后端模板渲染。而模板是直接在浏览器中打开文件夹,然后检查元素将代码拷贝下来,将列表部分换成模板格式文本。

遇到的问题:

图标无法正常显示

在浏览器打开文件路径,可以看到文件的图标的href是类似“moz-icon://.pdf?size=16”。但是我将这段代码直接给我的图片的href却无法正常显示(有大牛可以告诉我这是为什么吗)。于是我将图标下载下来放在和public同级的index_template_files文件夹里面。我的js文件是和public以及index_template_files同级的,但是我无论如何设置href都无法正常显示图标。后来发现我对于文件处理的时候,统一在路径前加了./public/,对于正常资源没有问题。但是对于图标不在public里面的就找不到文件了。于是在读取文件时,多了一个判断是否为图标文件。

效果

源代码

后端代码如下:

var http = require('http');
var url = require('url');
var fs = require('fs');
var path = require('path');
var mime = require('mime');
var template = require('art-template');
//basedir作为文件服务器的根目录,防止网上访问到程序源码
var basedir='public';
//这里是在创建服务器的时候就写入了回调函数,也可以后续在server.on('request',callback)中写
server = http.createServer(function(req,res){//decodeURI函数的功能就是为了将变成%序列的中文转回来var dirpath = decodeURI(url.parse(req.url).pathname);var template_data={};template_data['path']=dirpath;//如果是根目录,则不希望出现回到上层目录,所以不为根目录设置上层目录if (dirpath!=='/') {template_data['last_path']=path.dirname(dirpath);}//这里为了区分图标文件,图标文件放在不同的文件夹,需要特殊处理,图标文件是如:iconpdf.icon形式的文件if (dirpath.startsWith('/icon') && path.extname(dirpath)==='.icon') {f=fs.readFile('./'+path.join('index_template_files',dirpath),function(err,data){res.writeHead(200,{'Content-Type': mime.getType(dirpath)});res.end(data);});} else {try{var stat=fs.lstatSync('./'+path.join(basedir,dirpath));if (stat.isDirectory()) {var files=fs.readdirSync('./'+path.join(basedir,dirpath));template_data['items']=[];files.forEach(function(file){item={};item['file_name']=file;var file_stat=fs.lstatSync('./'+path.join(basedir,dirpath,file));item['file_type']=file_stat.isDirectory()?'dir':'file';item['file_sort']=(file_stat.isDirectory()?'1':'2')+file;item['file_path']=path.join(dirpath,file);item['file_path']=path.join(dirpath,file);item['file_icon']='icon'+path.extname(file).substr(1)+'.icon';item['size_sort']=file_stat.size;var logsize=Math.log2(file_stat.size);if (logsize<10) {item['size_value']=file_stat.size.toString()+'B';} else if (logsize<20) {item['size_value']=(file_stat.size/1024).toString()+'KB';} else if (logsize<30) {item['size_value']=(file_stat.size/1024/1024).toString()+'MB';} else if (logsize<40) {item['size_value']=(file_stat.size/1024/1024/1024).toString()+'GB';} else {item['size_value']=(file_stat.size/1024/1024/1024/1024).toString()+'TB';}item['time_sort']=file_stat.mtimeMs;item['time_date']=file_stat.mtime.toDateString();item['time_time']=file_stat.mtime.toTimeString();template_data['items'].push(item);});html=template(path.resolve('index_template.html'),template_data);res.end(html);} else {f=fs.readFile('./'+path.join(basedir,dirpath),function(err,data){res.writeHead(200,{'Content-Type': mime.getType(dirpath)});res.end(data);});}}catch(e){res.end(e.toString());}}}).listen(80,function(req,res) {console.log('start');
});

模板代码如下:

<!DOCTYPE html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="UTF-8">
<style type="text/css">
:root {font-family: sans-serif;
}
img {border: 0;
}
th {text-align: start;white-space: nowrap;
}
th > a {color: inherit;
}
table[order] > thead > tr > th {cursor: pointer;
}
table[order] > thead > tr > th::after {display: none;width: .8em;margin-inline-end: -.8em;text-align: end;
}
table[order="asc"] > thead > tr > th::after {content: "\2193"; /* DOWNWARDS ARROW (U+2193) */
}
table[order="desc"] > thead > tr > th::after {content: "\2191"; /* UPWARDS ARROW (U+2191) */
}
table[order][order-by="0"] > thead > tr > th:first-child > a ,
table[order][order-by="1"] > thead > tr > th:first-child + th > a ,
table[order][order-by="2"] > thead > tr > th:first-child + th + th > a {text-decoration: underline;
}
table[order][order-by="0"] > thead > tr > th:first-child::after ,
table[order][order-by="1"] > thead > tr > th:first-child + th::after ,
table[order][order-by="2"] > thead > tr > th:first-child + th + th::after {display: inline-block;
}
table.remove-hidden > tbody > tr.hidden-object {display: none;
}
td {white-space: nowrap;
}
table.ellipsis {width: 100%;table-layout: fixed;border-spacing: 0;
}
table.ellipsis > tbody > tr > td {padding: 0;overflow: hidden;text-overflow: ellipsis;
}
/* name */
/* name */
th:first-child {padding-inline-end: 2em;
}
/* size */
th:first-child + th {padding-inline-end: 1em;
}
td:first-child + td {text-align: end;padding-inline-end: 1em;
}
/* date */
td:first-child + td + td {padding-inline-start: 1em;padding-inline-end: .5em;
}
/* time */
td:first-child + td + td + td {padding-inline-start: .5em;
}
.symlink {font-style: italic;
}
.dir ,
.symlink ,
.file {margin-inline-start: 20px;
}
.dir::before ,
.file > img {margin-inline-end: 4px;margin-inline-start: -20px;max-width: 16px;max-height: 16px;vertical-align: middle;
}
.dir::before {content: url(resource://content-accessible/html/folder.png);
}
</style>
<link rel="stylesheet" media="screen, projection" type="text/css" href="chrome://global/skin/dirListing/dirListing.css">
<script type="application/javascript">'use strict';var gTable, gOrderBy, gTBody, gRows, gUI_showHidden;document.addEventListener("DOMContentLoaded", function() {gTable = document.getElementsByTagName("table")[0];gTBody = gTable.tBodies[0];if (gTBody.rows.length < 2)return;gUI_showHidden = document.getElementById("UI_showHidden");var headCells = gTable.tHead.rows[0].cells,hiddenObjects = false;function rowAction(i) {return function(event) {event.preventDefault();orderBy(i);}}for (var i = headCells.length - 1; i >= 0; i--) {var anchor = document.createElement("a");anchor.href = "";anchor.appendChild(headCells[i].firstChild);headCells[i].appendChild(anchor);headCells[i].addEventListener("click", rowAction(i), true);}if (gUI_showHidden) {gRows = Array.slice(gTBody.rows);hiddenObjects = gRows.some(row => row.className == "hidden-object");}gTable.setAttribute("order", "");if (hiddenObjects) {gUI_showHidden.style.display = "block";updateHidden();}}, "false");function compareRows(rowA, rowB) {var a = rowA.cells[gOrderBy].getAttribute("sortable-data") || "";var b = rowB.cells[gOrderBy].getAttribute("sortable-data") || "";var intA = +a;var intB = +b;if (a == intA && b == intB) {a = intA;b = intB;} else {a = a.toLowerCase();b = b.toLowerCase();}if (a < b)return -1;if (a > b)return 1;return 0;}function orderBy(column) {if (!gRows)gRows = Array.slice(gTBody.rows);var order;if (gOrderBy == column) {order = gTable.getAttribute("order") == "asc" ? "desc" : "asc";} else {order = "asc";gOrderBy = column;gTable.setAttribute("order-by", column);gRows.sort(compareRows);}gTable.removeChild(gTBody);gTable.setAttribute("order", order);if (order == "asc")for (var i = 0; i < gRows.length; i++)gTBody.appendChild(gRows[i]);elsefor (var i = gRows.length - 1; i >= 0; i--)gTBody.appendChild(gRows[i]);gTable.appendChild(gTBody);}function updateHidden() {gTable.className = gUI_showHidden.getElementsByTagName("input")[0].checked ?"" :"remove-hidden";}</script>
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAjFJREFUeNqsU8uOElEQPffR3XQ3ONASdBJCSBxHos5%2B3Bg3rvkCv8PElS78gPkO%2FATjQoUdO2ftrJiRh6aneTb9sOpC4weMN6lcuFV16pxDIfI8x12OYIDhcPiu2Wx%2B%2FHF5CW1Z6Jyegt%2FTNEWSJIjjGFEUIQxDrFYrWFSzXC4%2FdLvd95pRKpXKy%2BpRFZ7nwaWo1%2BsGnQG2260BKJfLKJVKGI1GEEJw7ateryd0v993W63WEwjgxfn5obGYzgCbzcaEbdsIggDj8Riu6z6iUk9SYZMSx8W0LMsM%2FSKK75xnJlIq80anQXdbEp0OhcPJ0eiaJnGRMEyyPDsAKKUM9clkYoDo3SZJzzSdp0VSKYmfV1co%2Bz580kw5KDIM8RbRfEnUf1HzxtQyMAGcaGruTKczMzEIaqhKifV6jd%2BzGQQB5llunF%2FM52BizC2K5sYPYvZcu653tjOM9O93wnYc08gmkgg4VAxixfqFUJT36AYBZGd6PJkFCZnnlBxMp38gqIgLpZB0y4Nph18lyWh5FFbrOSxbl3V4G%2BVB7T4ajYYxTyuLtO%2BCvWGgJE1Mc7JNsJEhvgw%2FQV4fo%2F24nbEsX2u1d5sVyn8sJO0ZAQiIYnFh%2BxrfLz%2Fj29cBS%2FO14zg3i8XigW3ZkErDtmKoeM%2BAJGRMnXeEPGKf0nCD1ydvkDzU9Jbc6OpR7WIw6L8lQ%2B4pQ1%2FlPF0RGM9Ns91Wmptk0GfB4EJkt77vXYj%2F8m%2B8y%2FkrwABHbz2H9V68DQAAAABJRU5ErkJggg%3D%3D">
<title>{{ path }} 的索引</title>
<!-- base href="file:///F:/hkc/nodeprojects/" -->
</head>
<body dir="ltr">
<h1>{{ path }} 的索引</h1>
{{ if last_path }}
<p id="UI_goUp"><a class="up" href="{{ last_path }}">回到上一层文件夹</a></p>
{{ /if }}
<p id="UI_showHidden" style="display:none"><label><input type="checkbox" checked="checked" onchange="updateHidden()">显示隐藏对象</label></p>
<table order=""><thead><tr><th><a href="">名称</a></th><th><a href="">大小</a></th><th colspan="2"><a href="">修改时间</a></th></tr></thead><tbody>
{{ each items }}
<tr><td sortable-data="{{ $value.file_sort }}"><table class="ellipsis"><tbody><tr><td><a class="{{ $value.file_type }}" href="{{ $value.file_path }}">{{ if $value.file_type==="file" }}<img src="{{ $value.file_icon }}" alt="文件: ">{{ /if }}{{ $value.file_name }}</a></td></tr></tbody></table></td><td sortable-data="{{ $value.size_sort }}">{{ $value.size_value }}</td><td sortable-data="{{ $value.time_sort }}">{{ $value.time_date }}</td><td>{{ $value.time_time }}</td>
</tr>
{{ /each }}
</tbody></table>
</body></html>

总结

  1. 通过这个小app的探究,熟悉了一些模块的用法,熟悉了后端渲染模板的用法。
  2. nodejs做的事情很底层,任何向你的服务器发出的请求,都是你自己处理的。所以不要自认为写对了图片路径就万事大吉了。也许你自己处理的方式不同,正确的路径就变成了错误的路径。请求路径和文件路径不是一回事。
  3. 代码质量肯定不行,不喜勿喷。不过非常希望大牛提出建设性意见!

nodejs搭建静态文件服务器相关推荐

  1. 中间件静态文件服务器,从koa-static中间件学习搭建静态文件服务器

    从koa和第,.年过事工宗据指数遍互业经搞断果会-static中间件学习搭建静态抖要支圈者器说是事天开的.年后编定功口小发还应久剑文件服务器 koa-作一新求抖直微圈send Static file ...

  2. nginx搭建静态文件服务器,利用nginx搭建静态资源服务器的方法步骤

    以windows为例,linux其实一样: 搭建静态资源服务器 我电脑上的work文件夹下面有很多图片,我想通过nginx搭建静态资源服务器,通过在地址栏输入ip+port的方式完成目录的映射 找到n ...

  3. 只需三分钟您就可以用nodejs搭建静态网页服务器(配置静态网页访问目录)

    Node.js 中文网Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境.Node.js 使用了一个事件驱动.非阻塞式 I/O 的模型,使其轻量又高效.Node.j ...

  4. nginx搭建静态文件服务器,Nginx 静态文件服务器搭建及autoindex模块解析

    导读 文章重点讲述nginx静态服务器搭建 ngx_http_autoindex_module ngx_http_autoindex_module模块处理以斜杠字符('/')结尾的请求,并生成目录列表 ...

  5. 自己搭建静态文件服务器,快速搭建静态服务器的几种方法

    作为一名前端开发人员,经常也是需要有一个静态服务器的.下面让我们来分分钟搭建自己的静态服务器吧 一:使用 http-server http-server 基于 Node,所以得先确保有 Node 环境 ...

  6. 使用Apache2 搭建静态文件服务器

    1.安装Apache2 sudo apt-get install apache2 2.修改Apache2端口(可以选择不修改) vi /etc/apache2/ports.conf #将80改为想要的 ...

  7. svn服务器搭建和使用_简单使用nodejs搭建一个静态服务器

    前提:系统安装nodejs 搭建步骤 使用nodejs搭建服务器,简单的来说可以分为三步: require相应的模块 创建服务器 配置端口 启动服务器 必要的nodejs模块 以下模块都是以 var ...

  8. Nginx 静态文件服务器搭建及autoindex模块解析

    ngx_http_autoindex_module ngx_http_autoindex_module模块处理以斜杠字符('/')结尾的请求,并生成目录列表. 当ngx_http_index_modu ...

  9. 《微信小游戏远程服务器本地搭建》——本地搭建IIS静态文件服务器

    本地文件服务器 前言 搭建背景 搭建需求 搭建流程 结尾 前言 开发游戏的同学们,经常都会遇到以下情况:当包体大于平台限制不被允许打包发布:建议将不必要的资源文件放在远程加载:打开发版本的包,没有合适 ...

最新文章

  1. mysql数据库oem_Oracle 11gR2学习之二(创建数据库及OEM管理篇)
  2. sql安装错误解决办法
  3. 计算机一级讲评,一级WPS Office——全国计算机等级考试专家讲评
  4. ASP.NET MVC案例教程(基于ASP.NET MVC beta)——第二篇:第一个页面
  5. bs架构 mysql_基于BS架构OA办公系统的设计(PHP,MySQL)(三人组)(含录像)
  6. python用sqlite数据库,python 中使用sqlite数据库
  7. 我对Linux输入输出重定向的小结
  8. MFC开发-待整理 --VS调试 不会命中断点,源代码与原始版本不同的解决办法
  9. ctypealpha php_PHP Ctype函数(转)
  10. 专升本高数——常用公式总结大全【补充扩展】
  11. mysql8.0.25安装配置教程(windows 64位)最详细
  12. ubuntu14.04 + dlib19.2+【 C++ 】+Face Landmark Detection
  13. 华硕 小布 类似机器人_“嗨 小布跟着我” | 华硕首款智能机器人“小布”正式发布...
  14. 你会他乡遇故知?-让自己慢下来(51)
  15. 如何解决电脑使用中任务栏“卡死”问题。
  16. lisp画弯箭头_在CAD中直接用命令画箭头
  17. Python系列 - pip管理工具
  18. cxfreeze 打包exe
  19. Fiddler抓包配置和使用(全网最详细教程)
  20. java毕业设计线上甜品店售卖系统Mybatis+系统+数据库+调试部署

热门文章

  1. 唐朝书法家有哪些人物?
  2. cn域名有哪些好处?
  3. 【转】一个老员工的离职忠告,7年职场经历的感悟
  4. Capture One Pro 10: Retouching Capture One Pro 10:修饰 Lynda课程中文字幕
  5. 【笔记】STM32F4xx 通用 I/O (GPIO)
  6. 3 编写程序打印下面的图案 java_编写程序打印下面的图案
  7. 来自闪闪宝石的光芒 - “宝石迷阵” x 信息检索
  8. 我爱你计算机语言编译,JavaSE-Quickstart
  9. 12干货!spring整合mybatis底层源码分析
  10. 解决无法获取到B站点赞数和播放量的解决办法