Базовый статический файловый сервер в NodeJS
Я пытаюсь создать статический файловый сервер в nodejs больше как упражнение для понимания узла, чем как идеальный сервер. Я хорошо знаю такие проекты, как Connect и node-static, и полностью намерен использовать эти библиотеки для более готового к работе кода, но мне также нравится понимать основы того, с чем я работаю. Имея это в виду, я включил небольшой сервер.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 Foundn');
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 ответов:
ваш основной сервер выглядит хорошо, за исключением:
есть
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()делает в основном это, он также приостанавливает / возобновляет исходный поток (в случае, если приемник медленнее). Вот исходный код
меньше
просто сначала перейдите в командную строку вашего проекта и используйте
$ npm install expressзатем напишите свое приложение.js код вот так:
var express = require('express'), app = express(), port = process.env.PORT || 4000; app.use(express.static(__dirname + '/public')); app.listen(port);затем вы создадите "общедоступную" папку, в которую вы помещаете свои файлы. Сначала я попробовал это сложнее, но вам нужно беспокоиться о типах mime, которые просто должны отображать материал, который занимает много времени, а затем беспокоиться о типах ответов и т. д. так далее. так далее.... Нет, спасибо.
Мне нравится понимать, что происходит под капотом, а также.
Я заметил несколько вещей в вашем коде, которые вы, вероятно, хотите очистить:
Он аварийно завершает работу, когда filename указывает на каталог, потому что существует true, и он пытается прочитать поток файлов. Я использовал fs.lstatSync для определения существования каталога.
Это не правильное использование кодов ответа HTTP (200, 404 и т. д.)
пока MimeType определяется (из расширения файла), он не устанавливается правильно в res.writeHead (как указал Стью)
для обработки специальных символов, вы, вероятно, хотите, чтобы unescape 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);
Я сделал функцию httpServer с дополнительными функциями для общего использования на основе @ Jeff Ward answer
- custtom dir
.html возвращает, если req = = = 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]))
the 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 есть и другие промежуточные программы, которые вы можете использовать.
Comments