Estou tentando criar um servidor de arquivos estático em nodejs mais como um exercício para entender o node do que como um servidor perfeito. Estou bem ciente de projetos como Connect e node-static e pretendo usar essas bibliotecas para obter mais código pronto para produção, mas também gosto de entender o básico com o que estou trabalhando. Com isso em mente, codifiquei um pequeno 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);
Minha pergunta é dupla
É esta a maneira "certa" de criar e transmitir html básico etc no node ou existe um método melhor / mais elegante / mais robusto?
O .pipe () no nó basicamente está fazendo o seguinte?
.
var fileStream = fs.createReadStream(filename);
fileStream.on('data', function (data) {
res.write(data);
});
fileStream.on('end', function() {
res.end();
});
Obrigado a todos!
fs.exists()
vez dopath.exists()
código acima. Felicidades! e sim! não se esqueçareturn
:fs.exists()
está obsoleto . Usefs.access()
ou ainda melhor como no caso de uso acimafs.stat()
,. 2)url.parse
está obsoleto ; use anew URL
interface mais recente .Respostas:
Seu servidor básico parece bom, exceto:
Falta uma
return
declaração.res.write('404 Not Found\n'); res.end(); return; // <- Don't forget to return here !!
E:
res.writeHead(200, mimeType);
deveria estar:
res.writeHead(200, {'Content-Type':mimeType});
Sim
pipe()
, basicamente faz isso, ele também pausa / retoma o fluxo de origem (no caso do receptor ser mais lento). Aqui está o código-fonte dapipe()
função: https://github.com/joyent/node/blob/master/lib/stream.jsfonte
Menos é mais
Basta ir ao prompt de comando primeiro em seu projeto e usar
Em seguida, escreva o código app.js assim:
var express = require('express'), app = express(), port = process.env.PORT || 4000; app.use(express.static(__dirname + '/public')); app.listen(port);
Em seguida, você criaria uma pasta "pública" onde colocaria seus arquivos. Eu tentei da maneira mais difícil primeiro, mas você precisa se preocupar com os tipos MIME, que é apenas mapear coisas que consomem muito tempo e depois se preocupar com os tipos de resposta, etc. etc. etc ... não, obrigado.
fonte
require('http')
na segunda linha?Também gosto de entender o que está acontecendo nos bastidores.
Percebi algumas coisas em seu código que você provavelmente deseja limpar:
Ele trava quando o nome do arquivo aponta para um diretório, porque existe é verdadeiro e tenta ler um fluxo de arquivo. Usei fs.lstatSync para determinar a existência do diretório.
Ele não está usando os códigos de resposta HTTP corretamente (200, 404 etc.)
Enquanto MimeType está sendo determinado (da extensão do arquivo), ele não está sendo definido corretamente em res.writeHead (como stewe apontou)
Para lidar com caracteres especiais, você provavelmente deseja desfazer o escape do uri
Segue cegamente links simbólicos (pode ser uma preocupação de segurança)
Diante disso, algumas das opções do apache (FollowSymLinks, ShowIndexes, etc) começam a fazer mais sentido. Atualizei o código do seu servidor de arquivos simples da seguinte maneira:
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);
fonte
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]))
fonte
Que tal este padrão, que evita verificar separadamente se o arquivo existe
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);
fonte
fileStream.on('open', ...
Fiz uma função httpServer com recursos extras para uso geral baseado na resposta de @Jeff Ward
Uso:
https://github.com/kenokabe/ConciseStaticHttpServer
Obrigado.
fonte
o módulo st facilita o serviço de arquivos estáticos. Aqui está um extrato de 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)
fonte
A resposta de @JasonSebring me indicou a direção certa, porém seu código está desatualizado. Aqui está como você faz isso com a
connect
versão mais recente.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);
No
connect
Repositório GitHub, existem outros middlewares que você pode usar.fonte
connect
documentação, é apenas umwrapper
paramiddleware
. Todos os outros itens interessantesmiddleware
são doexpress
repositório, portanto, tecnicamente, você pode usar essas APIs usando oexpress.use()
.