nodejs搭建静态文件服务器

用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里面的就找不到文件了。于是在读取文件时,多了一个判断是否为图标文件。

效果

nodejs搭建静态文件服务器_第1张图片

源代码

后端代码如下:

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');
});

模板代码如下:









{{ path }} 的索引



{{ path }} 的索引

{{ if last_path }}

回到上一层文件夹

{{ /if }} {{ each items }} {{ /each }}
名称 大小 修改时间
{{ if $value.file_type==="file" }}文件: {{ /if }}{{ $value.file_name }}
{{ $value.size_value }} {{ $value.time_date }} {{ $value.time_time }}

 

总结

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

你可能感兴趣的:(node)