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

我试图在nodejs中创build一个静态文件服务器,作为理解节点的一个练习,而不是一个完美的服务器。 我非常了解像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); 

我的问题是双重的

  1. 这是在节点创build和stream式传输基本html等的“正确”方式,还是有一个更好/更优雅/更强大的方法?

  2. .pipe()在节点基本上只是做下面的?

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

感谢大家!

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

    有一个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});

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

less即是多

只需在您的项目中首先使用命令提示符并使用

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

然后,您将创build一个“公共”文件夹放置您的文件。 我首先尝试了这种方法,但是你必须担心mimetypes,这些types只需要映射耗时的东西,然后担心响应types等。等等……不,谢谢。

我也喜欢理解发生了什么。

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

  • 当文件名指向一个目录时,它崩溃,因为存在是真的,它试图读取一个文件stream。 我用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); 

这种模式如何避免单独检查文件是否存在

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

我根据@Jeff Ward的回答制作了一个带有额外function的httpServer函数

  1. custtom dir
  2. index.html返回如果请求=== dir

用法:

 httpServer(dir).listen(port); 

https://github.com/kenokabe/ConciseStaticHttpServer

谢谢。

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

st模块使服务静态文件变得容易。 这里是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答案指出我正确的方向,但他的代码已经过时了。 这里是你如何使用最新的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仓库中还有其他可以使用的中间件。