Базовый статический файловый сервер в NodeJS - PullRequest
83 голосов
/ 01 сентября 2011

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

У меня двоякий вопрос

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

  2. Является ли .pipe () в узле просто следующим образом?

.

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

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

Ответы [ 8 ]

56 голосов
/ 18 августа 2012

Меньше - больше

Сначала зайдите в командную строку вашего проекта и используйте

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

Затем вы создадите «публичную» папку, в которую вы поместите свои файлы. Сначала я попробовал это сложнее, но вам нужно беспокоиться о типах пантомимы, которые просто должны отображать вещи, которые отнимают много времени, а затем беспокоиться о типах ответов и т. Д. И т. Д. И т. П. Нет.

44 голосов
/ 01 сентября 2011
  • Ваш базовый сервер выглядит хорошо, за исключением:

    Отсутствует оператор 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() делает в основном то, что он также приостанавливает / возобновляет исходный поток (весли приемник работает медленнее).Вот исходный код функции pipe(): https://github.com/joyent/node/blob/master/lib/stream.js

19 голосов
/ 28 августа 2012

Мне также нравится понимать, что происходит под капотом.

Я заметил в вашем коде несколько вещей, которые вы, вероятно, хотите очистить:

  • Этоаварийно завершает работу, когда имя файла указывает на каталог, потому что существует истинно и он пытается прочитать поток файла.Я использовал fs.lstatSync для определения существования каталога.

  • Он неправильно использует коды ответов HTTP (200, 404 и т. Д.)

  • Во время определения MimeType (из расширения файла) он не устанавливается правильно в res.writeHead (как указывалось в stewe)

  • Для обработки специальных символов вам, вероятно, понадобитсячтобы убрать URI

  • Он слепо следует символическим ссылкам (может быть проблемой безопасности)

Учитывая это, некоторые из параметров apache (FollowSymLinksShowIndexes и т. Д.) Начинают иметь больше смысла.Я обновил код вашего простого файлового сервера следующим образом:

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);
3 голосов
/ 18 февраля 2014

Как насчет этого шаблона, который позволяет отдельно не проверять, существует ли файл

        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);
2 голосов
/ 14 мая 2015
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]))
2 голосов
/ 05 августа 2013

Я сделал функцию httpServer с дополнительными функциями для общего пользования на основе ответа @Jeff Ward

  1. Custtom DIR
  2. index.html возвращает, если req === dir

Использование:

httpServer(dir).listen(port);

https://github.com/kenokabe/ConciseStaticHttpServer

Спасибо.

0 голосов
/ 05 декабря 2014

@ 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 есть и другие промежуточные программы, которые вы можете использовать.

0 голосов
/ 08 июля 2014

модуль 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...