简体   繁体   English

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

[英]Basic static file server in NodeJS

I'm trying to create a static file server in nodejs more as an exercise to understand node than as a perfect server. 我试图在nodejs中创建一个静态文件服务器,作为理解节点而不是完美服务器的练习。 I'm well aware of projects like Connect and node-static and fully intend to use those libraries for more production-ready code, but I also like to understand the basics of what I'm working with. 我非常了解Connect和node-static等项目,并且完全打算将这些库用于更多生产就绪的代码,但我也想了解我正在使用的基础知识。 With that in mind, I've coded up a small server.js: 考虑到这一点,我编写了一个小型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);

My question is twofold 我的问题是双重的

  1. Is this the "right" way to go about creating and streaming basic html etc in node or is there a better/more elegant/more robust method ? 这是在节点中创建和流式传输基本html等的“正确”方法,还是有更好/更优雅/更健壮的方法?

  2. Is the .pipe() in node basically just doing the following? 节点中的.pipe()基本上只是执行以下操作吗?

.

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

Thanks everyone! 感谢大家!

Less is more 少即是多

Just go command prompt first on your project and use 首先在项目中使用命令提示符并使用

$ npm install express

Then write your app.js code like so: 然后编写你的app.js代码,如下所示:

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

app.use(express.static(__dirname + '/public'));
app.listen(port);

You would then create a "public" folder where you place your files. 然后,您将创建一个放置文件的“公共”文件夹。 I tried it the harder way first but you have to worry about mime types which is just having to map stuff which is time consuming and then worry about response types, etc. etc. etc.... no thank you. 我首先尝试了更难的方法,但你必须担心mime类型,只需要映射耗时的东西,然后担心响应类型等等等....不,谢谢你。

  • Your basic server looks good, except: 您的基本服务器看起来不错,除了:

    There is a return statement missing. 缺少return声明。

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

    And: 和:

    res.writeHead(200, mimeType);

    should be: 应该:

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

  • Yes pipe() does basically that, it also pauses/resumes the source stream (in case the receiver is slower). 是的pipe()基本上就是这样,它还会暂停/恢复源流(如果接收器速度较慢)。 Here is the source code of the pipe() function: https://github.com/joyent/node/blob/master/lib/stream.js 以下是pipe()函数的源代码: https//github.com/joyent/node/blob/master/lib/stream.js

I like understanding what's going on under the hood as well. 我也喜欢了解引擎盖下发生的事情。

I noticed a few things in your code that you probably want to clean up: 我注意到你的代码中有一些你可能想要清理的东西:

  • It crashes when filename points to a directory, because exists is true and it tries to read a file stream. 当文件名指向目录时崩溃,因为exists为true并且它尝试读取文件流。 I used fs.lstatSync to determine directory existence. 我使用fs.lstatSync来确定目录是否存在。

  • It isn't using the HTTP response codes correctly (200, 404, etc) 它没有正确使用HTTP响应代码(200,404等)

  • While MimeType is being determined (from the file extension), it isn't being set correctly in res.writeHead (as stewe pointed out) 在确定MimeType时(从文件扩展名),它在res.writeHead中没有正确设置(正如stewe指出的那样)

  • To handle special characters, you probably want to unescape the uri 要处理特殊字符,你可能想要uricape uri

  • It blindly follows symlinks (could be a security concern) 盲目跟随符号链接(可能是一个安全问题)

Given this, some of the apache options (FollowSymLinks, ShowIndexes, etc) start to make more sense. 鉴于此,一些apache选项(FollowSymLinks,ShowIndexes等)开始变得更有意义。 I've update the code for your simple file server as follows: 我更新了简单文件服务器的代码,如下所示:

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

How about this pattern, which avoids checking separately that the file exists 这个模式怎么样,避免单独检查文件是否存在

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

I made a httpServer function with extra features for general usage based on @Jeff Ward answer 我根据@Jeff Ward的答案制作了一个具有额外功能的httpServer功能

  1. custtom dir custtom dir
  2. index.html returns if req === dir 如果req === dir,则返回index.html

Usage: 用法:

httpServer(dir).listen(port);

https://github.com/kenokabe/ConciseStaticHttpServer https://github.com/kenokabe/ConciseStaticHttpServer

Thanks. 谢谢。

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]))

the st module makes serving static files easy. st模块使服务静态文件变得容易。 Here is an extract of README.md: 这是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)

@JasonSebring answer pointed me in the right direction, however his code is outdated. @JasonSebring的回答指出了我正确的方向,但是他的代码已经过时了。 Here is how you do it with the newest connect version. 以下是使用最新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);

In connect GitHub Repository there are other middlewares you can use. connect GitHub存储库中 ,您可以使用其他中间件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM