Я пытаюсь создать статический файловый сервер в nodejs скорее как упражнение для понимания node, чем как идеальный сервер. Я хорошо знаком с такими проектами, как 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);
У меня двоякий вопрос
Является ли это «правильным» способом создания и потоковой передачи базового HTML и т. Д. В узле, или есть лучший / более элегантный / более надежный метод?
Является ли .pipe () в узле просто следующим?
.
var fileStream = fs.createReadStream(filename);
fileStream.on('data', function (data) {
res.write(data);
});
fileStream.on('end', function() {
res.end();
});
Спасибо всем!
fs.exists()
вместоpath.exists()
в приведенном выше коде. Ура! и да! не забывайтеreturn
:fs.exists()
является устаревшим . Использованиеfs.access()
или даже лучше , так как для вышеупомянутого случая использованияfs.stat()
. 2)url.parse
является устаревшим ;new URL
вместо этого используйте более новый интерфейс.Ответы:
Ваш базовый сервер выглядит хорошо, за исключением:
Отсутствует
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источник
Меньше - больше
Просто зайдите сначала в командную строку своего проекта и используйте
Затем напишите свой код app.js следующим образом:
var express = require('express'), app = express(), port = process.env.PORT || 4000; app.use(express.static(__dirname + '/public')); app.listen(port);
Затем вы должны создать «общедоступную» папку, в которую вы помещаете свои файлы. Сначала я попробовал более сложный способ, но вам нужно беспокоиться о типах mime, которые просто должны отображать вещи, которые отнимают много времени, а затем беспокоиться о типах ответов и т. Д. И т. Д., Нет, спасибо.
источник
require('http')
во второй строке?Мне также нравится понимать, что происходит под капотом.
Я заметил в вашем коде несколько вещей, которые вы, вероятно, захотите исправить:
Он вылетает, когда имя файла указывает на каталог, потому что существует истинное значение и пытается прочитать файловый поток. Я использовал fs.lstatSync для определения существования каталога.
Он неправильно использует коды ответа HTTP (200, 404 и т. Д.)
Пока MimeType определяется (по расширению файла), он неправильно установлен в res.writeHead (как указал Стю)
Для обработки специальных символов вы, вероятно, захотите отменить экранирование 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 mimeType = mimeTypes[path.extname(filename).match(/\.([^\.]+)$/)[1]];
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]))
источник
Как насчет этого шаблона, который позволяет избежать отдельной проверки существования файла?
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);
источник
fileStream.on('open', ...
Я сделал функцию httpServer с дополнительными функциями для общего использования на основе ответа @Jeff Ward
Применение:
https://github.com/kenokabe/ConciseStaticHttpServer
Спасибо.
источник
модуль й облегчает обслуживание статических файлов. Вот выдержка из 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 есть и другие промежуточные программы, которые вы можете использовать.источник
connect
документацию, то это толькоwrapper
дляmiddleware
. Все остальные интересные вещиmiddleware
взяты изexpress
репозитория, поэтому технически вы можете использовать эти API с помощьюexpress.use()
.