85 votes

Serveur de fichiers statique de base dans NodeJS

Je suis en train de créer un fichier statique serveur nodejs plus comme un exercice pour comprendre nœud que comme un serveur idéal. Je suis bien conscient de projets comme le Connecter et le nœud-statique et ont l'intention d'utiliser ces bibliothèques pour plus prêt à la production de code, mais j'aime aussi comprendre les bases de ce que je suis en train de travailler avec. Avec cela à l'esprit, j'ai codé un petit 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);

Ma question est double

  1. Est-ce la "bonne" façon d'aller sur la création et la diffusion en continu de base en html etc nœud ou est-il mieux/plus élégant/méthode plus solide ?

  2. Est le .pipe() dans le nœud fondamentalement juste de faire ce qui suit?

.

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

Merci à tous!

57voto

Jason Sebring Points 4309

Cela semble plus facile et il a quelques extras sympas si vous en avez besoin.

Juste aller de l'invite de commande en premier sur votre projet et à utiliser

> npm install connect

Ensuite, écrivez votre app.js code comme ceci:

var connect = require('connect'),
    http = require('http');

connect()
    .use(connect.static('public'))
    .use(connect.directory('public')) // lists directory: added onaclove2000 credit
    .listen(3000);

Vous pouvez alors créer un "public" du dossier où vous placez vos fichiers. J'ai essayé le plus difficile abord, mais aussi de nombreux goodies manquant. Connect est très populaire.

RÉVISION: Node.js n'est pas recommandé comme un fichier système, car il ya beaucoup de meilleures alternatives à l'aide de CA, nginx, Apache, IIS, etc. Nœud brille lorsque vous faites du contenu dynamique qui tire les ressources du réseau. De son mieux pour mettre vos fichiers statiques ailleurs et laissez Nœud de faire ce qu'il fait de mieux, si possible.

44voto

stewe Points 14623
  • Votre serveur de base semble bonne, à l'exception:

    Il y a un return déclaration manquante.

    res.write('404 Not Found\n');
    res.end();
    return; // <- Don't forget to return here !!
    

    Et:

    res.writeHead(200, mimeType);

    devrait être:

    res.writeHead(200, {'Content-Type':mimeType});

  • Oui pipe() n'en gros, il a aussi une pause/reprise de la source de diffusion (dans le cas où le récepteur est plus lent). Voici le code source de l' pipe() fonction de: https://github.com/joyent/node/blob/master/lib/stream.js

19voto

Jeff Ward Points 2849

J'aime comprendre ce qui se passe sous le capot.

J'ai remarqué quelques petites choses dans votre code que vous voulez probablement pour nettoyer:

  • Il se bloque lorsque le nom de fichier pointe vers un répertoire, car il existe est vrai et il essaie de lire un fichier de flux. J'ai utilisé de la fs.lstatSync pour déterminer l'existence d'un répertoire.

  • Il n'est pas en utilisant les codes de réponse HTTP correctement (200, 404, etc)

  • Tout type mime est déterminé (à partir de l'extension de fichier), elle n'est pas définie correctement dans res.writeHead (comme stewe souligné)

  • Pour gérer les caractères spéciaux, vous voulez sans doute de ne pas encoder les uri

  • Il suit aveuglément les liens symboliques (peut-être un problème de sécurité)

Compte tenu de cela, certains de apache options (options FollowSymLinks, ShowIndexes, etc) commencent à faire plus de sens. J'ai mis à jour le code pour votre simple serveur de fichiers comme suit:

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

3voto

Aerik Points 1112

Que diriez-vous de ce modèle, qui évite de vérifier séparément que le fichier 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('end', function() {
            console.log('sent file ' + filename);
            response.end("");
        });
        fileStream.pipe(response);
 

je ne sais pas si la réponse est vraiment nécessaire, mais cela ne semble pas poser de problèmes ...

2voto

Ken OKABE Points 627

J'ai créé une fonction httpServer avec des fonctionnalités supplémentaires pour une utilisation générale basée sur la réponse @Jeff Ward

  1. custtom dir
  2. index.html renvoie si req === dir

Usage:

 httpServer(dir).listen(port);
 

https://github.com/kenokabe/ConciseStaticHttpServer

Merci.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X