http - proyecto - Servidor de archivos estático básico en NodeJS
servidor http node js (8)
Estoy tratando de crear un servidor de archivos estáticos en nodejs más como un ejercicio para entender el nodo que como un servidor perfecto. Conozco bien proyectos como Connect y node-static y tengo la intención de usar esas bibliotecas para obtener más código listo para producción, pero también me gusta entender los conceptos básicos de lo que estoy trabajando. Con eso en mente, he codificado un pequeño servidor.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);
Mi pregunta es doble
¿Es esta la manera "correcta" de crear y transmitir html básico, etc. en un nodo o hay un método mejor / más elegante / más robusto?
¿El .pipe () en el nodo básicamente hace lo siguiente?
.
var fileStream = fs.createReadStream(filename);
fileStream.on(''data'', function (data) {
res.write(data);
});
fileStream.on(''end'', function() {
res.end();
});
¡Gracias a todos!
Menos es más
Simplemente ingrese el símbolo del sistema primero en su proyecto y use
$ npm install express
Luego escribe tu código app.js así:
var express = require(''express''),
app = express(),
port = process.env.PORT || 4000;
app.use(express.static(__dirname + ''/public''));
app.listen(port);
Luego, crearía una carpeta "pública" donde colocaría sus archivos. Lo intenté de la manera más difícil primero, pero tienes que preocuparte por los tipos de mimo, que es solo tener que mapear cosas que consumen mucho tiempo y luego preocuparte por los tipos de respuesta, etc. etc. etc ... no, gracias.
¿Qué hay de este patrón, que evita verificar por separado que el archivo 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);
El módulo st hace que sea más fácil servir archivos estáticos. Aquí hay un extracto 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)
Hice una función httpServer con funciones adicionales para uso general basadas en la respuesta de @Jeff Ward
- custtom dir
- index.html devuelve si req === dir
Uso:
httpServer(dir).listen(port);
https://github.com/kenokabe/ConciseStaticHttpServer
Gracias.
La respuesta de @JasonSebring me indicó la dirección correcta, sin embargo, su código está desactualizado. Así es como lo haces con la versión de connect
más nueva.
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);
En connect
GitHub Repository hay otros middlewares que puede usar.
Me gusta entender lo que sucede debajo del capó también.
Noté algunas cosas en tu código que probablemente quieras limpiar:
Se bloquea cuando el nombre del archivo apunta a un directorio, porque exists es verdadero e intenta leer una secuencia de archivos. Usé fs.lstatSync para determinar la existencia del directorio.
No está utilizando correctamente los códigos de respuesta HTTP (200, 404, etc.)
Mientras se determina MimeType (desde la extensión del archivo), no se está configurando correctamente en res.writeHead (como Stewe señaló)
Para manejar caracteres especiales, es probable que desee volver a abrir el uri
Sigue ciegamente los enlaces simbólicos (podría ser un problema de seguridad)
Dado esto, algunas de las opciones de apache (FollowSymLinks, ShowIndexes, etc.) comienzan a tener más sentido. Actualicé el código para su servidor de archivos simple de la siguiente manera:
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 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]))
Su servidor básico se ve bien, excepto:
Hay una declaración de
return
faltante.res.write(''404 Not Found/n''); res.end(); return; // <- Don''t forget to return here !!
Y:
res.writeHead(200, mimeType);
debiera ser:
res.writeHead(200, {''Content-Type'':mimeType});
Yes
pipe()
básicamente hace eso, también hace una pausa / reanuda la transmisión de la fuente (en caso de que el receptor sea más lento). Aquí está el código fuente de la funciónpipe()
: https://github.com/joyent/node/blob/master/lib/stream.js