NodeJS中的基本静态文件服务器

sla*_*ote 84 webserver http node.js

我试图在nodejs中创建一个静态文件服务器,作为理解节点而不是完美服务器的练习.我非常了解Connect和node-static等项目,并且完全打算将这些库用于更多生产就绪的代码,但我也想了解我正在使用的基础知识.考虑到这一点,我编写了一个小型server.js:

var http = require('http'),
    url = require('url'),
    path = require('path'),
    fs = require('fs');
var mimeTypes = {
    "html": "text/html",
    "jpeg": "image/jpeg",
    "jpg": "image/jpeg",
    "png": "image/png",
    "js": "text/javascript",
    "css": "text/css"};

http.createServer(function(req, res) {
    var uri = url.parse(req.url).pathname;
    var filename = path.join(process.cwd(), uri);
    path.exists(filename, function(exists) {
        if(!exists) {
            console.log("not exists: " + filename);
            res.writeHead(200, {'Content-Type': 'text/plain'});
            res.write('404 Not Found\n');
            res.end();
        }
        var mimeType = mimeTypes[path.extname(filename).split(".")[1]];
        res.writeHead(200, mimeType);

        var fileStream = fs.createReadStream(filename);
        fileStream.pipe(res);

    }); //end path.exists
}).listen(1337);
Run Code Online (Sandbox Code Playgroud)

我的问题是双重的

  1. 这是在节点中创建和流式传输基本html等的"正确"方法,还是有更好/更优雅/更健壮的方法?

  2. 节点中的.pipe()基本上只是执行以下操作吗?

.

var fileStream = fs.createReadStream(filename);
fileStream.on('data', function (data) {
    res.write(data);
});
fileStream.on('end', function() {
    res.end();
});
Run Code Online (Sandbox Code Playgroud)

感谢大家!

Jas*_*ing 56

少即是多

首先在项目中使用命令提示符并使用

$ npm install express
Run Code Online (Sandbox Code Playgroud)

然后编写你的app.js代码,如下所示:

var express = require('express'),
app = express(),
port = process.env.PORT || 4000;

app.use(express.static(__dirname + '/public'));
app.listen(port);
Run Code Online (Sandbox Code Playgroud)

然后,您将创建一个放置文件的"公共"文件夹.我首先尝试了更难的方法,但你必须担心mime类型,只需要映射耗时的东西,然后担心响应类型等等等....不,谢谢你.

  • 如果你想要目录列表,只需在connect.static行后面添加.use(connect.directory('public')),用你的路径替换public.对不起劫持,但我认为它为我解决了问题. (3认同)
  • 您不妨“使用 jQuery”!这不是对OP问题的回答,而是对一个甚至不存在的问题的解决方案。OP 表示,这个实验的目的是学习 Node.js。 (3认同)
  • +1使用经过测试的代码而不是自己编写代码有很多话要说. (2认同)
  • 关于理解内部结构和滚动自己的代码,还有很多话要说,而不是使用完全有效且经过测试的代码,这些代码是根据*他们*对什么是好的抽象和好的架构的理解在别人的头脑中设计的。 (2认同)

ste*_*ewe 44

  • 您的基本服务器看起来不错,除了:

    有一个return声明缺失.

    res.write('404 Not Found\n');
    res.end();
    return; // <- Don't forget to return here !!
    
    Run Code Online (Sandbox Code Playgroud)

    和:

    res.writeHead(200, mimeType);

    应该:

    res.writeHead(200, {'Content-Type':mimeType});

  • 是的pipe(),基本上是这样,它还会暂停/恢复源流(如果接收器速度较慢).以下是该pipe()函数的源代码:https://github.com/joyent/node/blob/master/lib/stream.js

  • 不是那个擦吗?如果你自己编写,你就会要求这些类型的错误.良好的学习,但我正在学习欣赏"连接",而不是自己动手.这个页面的问题是人们正在寻找如何做一个简单的文件服务器和堆栈溢出首先出现.这个答案是对的,但人们不是在寻找它,只是一个简单的答案.我必须自己找出更简单的一个,所以把它放在这里. (5认同)
  • 如果文件名像blah.blah.css会怎么样? (2认同)
  • 在那种情况下,mimeType应该是xP (2认同)

Jef*_*ard 19

我也喜欢了解引擎盖下发生的事情.

我注意到你的代码中有一些你可能想要清理的东西:

  • 当文件名指向目录时崩溃,因为exists为true并且它尝试读取文件流.我使用fs.lstatSync来确定目录是否存在.

  • 它没有正确使用HTTP响应代码(200,404等)

  • 在确定MimeType时(从文件扩展名),它在res.writeHead中没有正确设置(正如stewe指出的那样)

  • 要处理特殊字符,你可能想要uricape uri

  • 盲目跟随符号链接(可能是一个安全问题)

鉴于此,一些apache选项(FollowSymLinks,ShowIndexes等)开始变得更有意义.我更新了简单文件服务器的代码,如下所示:

var http = require('http'),
    url = require('url'),
    path = require('path'),
    fs = require('fs');
var mimeTypes = {
    "html": "text/html",
    "jpeg": "image/jpeg",
    "jpg": "image/jpeg",
    "png": "image/png",
    "js": "text/javascript",
    "css": "text/css"};

http.createServer(function(req, res) {
  var uri = url.parse(req.url).pathname;
  var filename = path.join(process.cwd(), unescape(uri));
  var stats;

  try {
    stats = fs.lstatSync(filename); // throws if path doesn't exist
  } catch (e) {
    res.writeHead(404, {'Content-Type': 'text/plain'});
    res.write('404 Not Found\n');
    res.end();
    return;
  }


  if (stats.isFile()) {
    // path exists, is a file
    var mimeType = mimeTypes[path.extname(filename).split(".").reverse()[0]];
    res.writeHead(200, {'Content-Type': mimeType} );

    var fileStream = fs.createReadStream(filename);
    fileStream.pipe(res);
  } else if (stats.isDirectory()) {
    // path exists, is a directory
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.write('Index of '+uri+'\n');
    res.write('TODO, show index?\n');
    res.end();
  } else {
    // Symbolic link, other?
    // TODO: follow symlinks?  security?
    res.writeHead(500, {'Content-Type': 'text/plain'});
    res.write('500 Internal server error\n');
    res.end();
  }

}).listen(1337);
Run Code Online (Sandbox Code Playgroud)

  • 我可以建议"var mimeType = mimeTypes [path.extname(filename).split(".").reverse()[0]];" 代替?一些文件名有多个"." 例如"my.cool.video.mp4"或"download.tar.gz" (4认同)