首页 文章

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

提问于
浏览
82

我试图在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);

我的问题是双重的

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

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

.

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

感谢大家!

8 回答

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

    缺少 return 语句 .

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

    和:

    res.writeHead(200, mimeType);

    应该:

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

  • 2

    少即是多

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

    $ npm install express
    

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

    var express = require('express'),
    app = express(),
    port = process.env.PORT || 4000;
    
    app.use(express.static(__dirname + '/public'));
    app.listen(port);
    

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

  • 3

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

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

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

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

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

    • 要处理特殊字符,您可能想要浏览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);
    
  • 2

    这个模式怎么样,避免单独检查文件是否存在

    var fileStream = fs.createReadStream(filename);
            fileStream.on('error', function (error) {
                response.writeHead(404, { "Content-Type": "text/plain"});
                response.end("file not found");
            });
            fileStream.on('open', function() {
                var mimeType = mimeTypes[path.extname(filename).split(".")[1]];
                response.writeHead(200, {'Content-Type': mimeType});
            });
            fileStream.on('end', function() {
                console.log('sent file ' + filename);
            });
            fileStream.pipe(response);
    
  • 44

    我根据@Jeff Ward的答案制作了一个具有额外功能的httpServer功能

    • custtom dir
      如果req === dir,
    • index.html会返回

    Usage:

    httpServer(dir).listen(port);
    

    https://github.com/kenokabe/ConciseStaticHttpServer

    谢谢 .

  • 0
    var http = require('http')
    var fs = require('fs')
    
    var server = http.createServer(function (req, res) {
      res.writeHead(200, { 'content-type': 'text/plain' })
    
      fs.createReadStream(process.argv[3]).pipe(res)
    })
    
    server.listen(Number(process.argv[2]))
    
  • 0

    st module使得提供静态文件变得容易 . 这是README.md的摘录:

    var mount = st({ path: __dirname + '/static', url: '/static' })
    http.createServer(function(req, res) {
      var stHandled = mount(req, res);
      if (stHandled)
        return
      else
        res.end('this is not a static file')
    }).listen(1338)
    
  • 55

    @JasonSebring的回答指出了我正确的方向,但是他的代码已经过时了 . 以下是使用最新 connect 版本的方法 .

    var connect = require('connect'),
        serveStatic = require('serve-static'),
        serveIndex = require('serve-index');
    
    var app = connect()
        .use(serveStatic('public'))
        .use(serveIndex('public', {'icons': true, 'view': 'details'}))
        .listen(3000);
    

    connect GitHub Repository中,您可以使用其他中间件 .

相关问题