Базовый статический файловый сервер в 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);


мой вопрос двоякий




  1. это "правильный" путь создание и потоковая передача базового html и т. д. В узле или есть лучший / более элегантный / более надежный метод ?


  2. - Это .pipe() в узле в основном просто делает следующее?



.



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


спасибо всем!

718   8  

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

  1. custtom dir
  2. .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

    Ничего не найдено.