美文网首页前端开发那些事
使用Node.js搭建简单静态文件服务器

使用Node.js搭建简单静态文件服务器

作者: 龍太 | 来源:发表于2016-11-15 21:15 被阅读0次

    这半个多月一直在学Node.js,还是在入门阶段,不过已经对Node很感兴趣了。这里介绍一个简单的静态文件服务器,总结一下心得体会。为什么说简单呢,因为虽然基本功能都有,但是没加路由,还有没考虑一些安全性的东西。后面我会继续来总结完善。

    本文参考了Node大神朴灵11年写的一篇博文(强烈建议读一读,虽然有一些接口有些老,但是搭建服务器的思路,各方面都有涉及),还有这位大神前辈的博客,以及Node.js 6.x版本的文档,stackoverflow一些答案。
    如果哪里说得不对或者哪里有问题,请劳烦您指正,我会虚心接受。

    正文如下:

    一个Web服务器应具备以下几个功能:

    1、能显示以.html/.htm结尾的Web页面

    2、能直接打开以.js/.css/.json/.text结尾的文件内容

    3、显示图片资源

    4、自动下载以.apk/.docx/.zip结尾的文件

    5、形如http://xxx.com/a/b/ , 则查找b目录下是否有index.html,如果有就显示,如果没有就列出该目录下的所有文件及文件夹,并可以进一步访问。

    6、形如http://xxx.com/a/b, 则作301重定向到http://xxx.com/a/b/ , 这样可以解决内部资源引用错位的问题。

    总体的思路如下:

    1.先加载需要用到的几个模块 url(解析request,截取路径) path(解析路径) fs(文件读写操作) http(起服务器)

    2.切出来请求的url和路径 (记得解码,防止中文乱码)

    3.根据路径有无扩展名以及是否以“/”结尾作判断,重定向

    4.根据路径来查找资源文件

    OK,接下来上代码,我有详细的标注注释(咳,方便以后来查漏补缺)

    前面有提到参考的那两篇博文的年代有些久远(其实也就4,5年前..),以致一些接口6.x版本的Node.js已经不支持了,或者一些方法近些年有了最佳实践。

    说一下重构的地方:
    1.判断路径类型,不使用fs.exist(),而是换成fs.stat方法

    2.将回调换成了箭头函数。

    3.我一直没查到getContentType这个方法.. 所以还是使用mime映射来传入content-type 其实已经专门有mime模块来处理这个问题了。

    4.做了一下模块化处理

    第一个模块: app.js 启动模块

    "use strict";
    //加载所需要的模块
    var http = require('http');
    
    var processRequest = require('./server');
    
    //创建服务,这里很机智的把对response和request的处理封装成一个匿名函数,传入createServer中
    //也可以直接在里面写,但是看起来不是很整洁
    var httpServer = http.createServer((req, res) => {
        processRequest(req, res);
    });
    
    var port = 8080;
    
    //指定一个监听的接口
    httpServer.listen(port, function() {
    
        console.log(`app is running at port:${port}`);
    });
    

    第二个模块:mime.js 存放类型映射

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

    第三个模块,也是我们的核心模块 server.js

    var url = require('url');
    
    var fs = require('fs');
    
    var path = require('path');
    
    var mime = require('./mime');
    
    function processRequest(request, response) {
    
    
        //request里面切出标识符字符串
        var requestUrl = request.url;
        //url模块的parse方法 接受一个字符串,返回一个url对象,切出来路径
        var pathName = url.parse(requestUrl).pathname;
    
        //对路径解码,防止中文乱码
        var pathName = decodeURI(pathName);
    
        //解决301重定向问题,如果pathname没以/结尾,并且没有扩展名
        if (!pathName.endsWith('/') && path.extname(pathName) === '') {
    
            pathName += '/';
            var redirect = "http://" + request.headers.host + pathName;
            response.writeHead(301, {
                location: redirect
            });
            //response.end方法用来回应完成后关闭本次对话,也可以写入HTTP回应的具体内容。
            response.end();
        };
    
        //获取资源文件的绝对路径
        var filePath = path.resolve(__dirname + pathName);
        console.log(filePath);
        //获取对应文件的文档类型
        //我们通过path.extname来获取文件的后缀名。由于extname返回值包含”.”,所以通过slice方法来剔除掉”.”,
        //对于没有后缀名的文件,我们一律认为是unknown。
        var ext = path.extname(pathName);
        ext = ext ? ext.slice(1) : 'unknown';
    
        //未知的类型一律用"text/plain"类型
        var contentType = mime[ext] || "text/plain";
    
        fs.stat(filePath, (err, stats) => {
    
            if (err) {
                response.writeHead(404, { "content-type": "text/html" });
                response.end("<h1>404 Not Found</h1>");
            };
            //没出错 并且文件存在
            if (!err && stats.isFile()) {
    
                response.writeHead(200, { "content-type": contentType });
                //建立流对象,读文件
                var stream = fs.createReadStream(filePath);
                //错误处理
                stream.on('error', function() {
    
                    response.writeHead(500, { "content-type": contentType });
    
                    response.end("<h1>500 Server Error</h1>");
    
                });
                //读取文件
                stream.pipe(response);
                //response.end();  这个地方有坑,加了会关闭对话,看不到内容了
            };
            //如果路径是目录
            if (!err && stats.isDirectory()) {
    
                var html = " <head><meta charset = 'utf-8'/></head>";
                //读取该路径下文件
                fs.readdir(filePath, (err, files) => {
                    if (err) {
                        console.log("读取路径失败!");
                    } else {
    
                        // files.foreach(function (file) {
                        // //做成一个链接表,方便用户访问
                        // html+=`<div><a href="${file}">${file}</a></div>`;
                        //  });
    
                        for (var file of files) {
                            if (file === "index.html") {
    
                                response.writeHead(200, { "content-type": "text/html" });
                                response.end(file);
    
                                break;
                            };
                            html += `<div><a href='${file}'>${file}</a></div>`;
                            console.log(html);
    
                        }
                        response.writeHead(200, { "content-type": "text/html" });
                        response.end(html);
                    };
    
                });
    
    
            };
    
        });
    
    };
    
    module.exports = processRequest;
    
        这里有几个细节的地方值得注意,一个是如何判断并实现重定向的,第二个是如何来判断content-type的。第三个要注意异步回调的执行顺序问题,有个坑就在传html那里。
        再说一个小坑吧,response.end()这个方法我理解的不够深,这个方法是用来关闭对话或者向response的body部分传内容,我把它放在了stream操作的下面,结果可想而知...  所以再涉及到文件读写时,一定要注意这个地方。
    
    下面是实现截图:
    
    1.这是我的目录,不用管那个vscode,那是visual studio code文件配置目录
    
    ![1.png](https://img.haomeiwen.com/i3373032/ffc04d2fc246ad97.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    2.服务器启动在8080端口
    
    ![2.png](https://img.haomeiwen.com/i3373032/9f44b9d0b7329c7a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    3.使用这个地址
    
    ![3.png](https://img.haomeiwen.com/i3373032/18056b5020add779.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    4.打开调试工具,可以发现Head部分是301,也就是发生了重定向
    
    ![4.png](https://img.haomeiwen.com/i3373032/8bdef90683b18238.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    5.来看看网页内容,可以看到,我们得到了该目录下可以访问的文件条目
    
    ![5.png](https://img.haomeiwen.com/i3373032/cb9c9e1934c412ef.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    6.最后,控制台信息
    
    ![6.png](https://img.haomeiwen.com/i3373032/421376c5ef9f7914.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    
    OK  就是这样。欢迎收看你的月亮我的心,好男人就是我~ 我们下周同一时间再会~
    PS:如果本文有错误的地方请您一定要指出来,我会虚心接受,万分感谢。~~

    相关文章

      网友评论

        本文标题:使用Node.js搭建简单静态文件服务器

        本文链接:https://www.haomeiwen.com/subject/mlslpttx.html