Comment servir une image en utilisant nodejs

J’ai un logo qui réside au public / images / logo.gif. Voici mon code nodejs.

http.createServer(function(req, res){ res.writeHead(200, {'Content-Type': 'text/plain' }); res.end('Hello World \n'); }).listen(8080, '127.0.0.1'); 

Cela fonctionne mais quand je demande localhost: 8080 / logo.gif alors je n’ai évidemment pas le logo.

Quels changements dois-je apporter pour servir une image?

Je suis d’accord avec les autres affiches que finalement, vous devriez utiliser un framework, tel qu’Express .. mais vous devez d’abord comprendre comment faire quelque chose de fondamental comme celui-ci sans bibliothèque, pour vraiment comprendre ce que la bibliothèque les étapes sont

  1. Analyser la requête HTTP entrante pour voir le chemin demandé par l’utilisateur
  2. Ajouter un chemin dans une instruction conditionnelle pour que le serveur réponde à
  3. Si l’image est demandée, lisez le fichier image du disque.
  4. Servir l’image type-contenu dans un en-tête
  5. Servir le contenu de l’image dans le corps

Le code ressemblerait à ceci (non testé)

 fs = require('fs'); http = require('http'); url = require('url'); http.createServer(function(req, res){ var request = url.parse(req.url, true); var action = request.pathname; if (action == '/logo.gif') { var img = fs.readFileSync('./logo.gif'); res.writeHead(200, {'Content-Type': 'image/gif' }); res.end(img, 'binary'); } else { res.writeHead(200, {'Content-Type': 'text/plain' }); res.end('Hello World \n'); } }).listen(8080, '127.0.0.1'); 

Mise à jour 2016

Exemples avec Express et sans Express qui fonctionnent réellement

Cette question a plus de 5 ans mais chaque réponse pose quelques problèmes .

TL; DR

Faites défiler les exemples pour servir une image avec:

  1. express.static
  2. express
  3. connect
  4. http
  5. net

Tous les exemples sont également sur GitHub: https://github.com/rsp/node-static-http-servers

Les résultats des tests sont disponibles sur Travis: https://travis-ci.org/rsp/node-static-http-servers

introduction

Après plus de 5 ans depuis que cette question a été posée, il n’y a qu’une seule réponse correcte par generalhenry, mais même si cette réponse ne pose aucun problème avec le code, elle semble avoir des problèmes de réception . Il a été dit que cela n’expliquait pas grand chose d’autre que la manière de compter sur quelqu’un pour faire le travail et le fait que beaucoup de personnes aient voté ce commentaire montre clairement que beaucoup de choses ont besoin de clarification.

Tout d’abord, une bonne réponse à “Comment servir des images avec Node.js” n’est pas d’implémenter un serveur de fichiers statique à partir de rien et de le faire mal. Une bonne réponse consiste à utiliser un module comme Express qui fait correctement le travail .

Il convient de noter que le fait d’utiliser le module http dépend déjà de quelqu’un d’autre pour faire le travail. Si quelqu’un ne veut pas faire confiance à qui que ce soit pour faire le travail, alors au moins les sockets TCP bruts doivent être utilisés – ce que je fais dans l’un des exemples ci-dessous.

Un problème plus grave est que toutes les réponses qui utilisent le module http sont cassées . Ils introduisent des conditions de course , une résolution de chemin non sécurisée qui mènera à une vulnérabilité de parcours , bloquant les E / S qui ne répondront à aucune demande simultanée et d’autres problèmes subtils – ils sont complètement brisés en tant qu’exemples de la question posée et pourtant, ils utilisent déjà l’abstraction fournie par le module http au lieu d’utiliser les sockets TCP, de sorte qu’ils ne font même pas tout ce qu’ils prétendent.

Si la question était “Comment implémenter un serveur de fichiers statique en partant de zéro, en tant qu’exercice d’apprentissage”, alors répondez par tous les moyens – mais même alors, nous devrions nous attendre à ce qu’ils soient au moins corrects . De plus, il n’est pas déraisonnable de supposer que quelqu’un qui veut servir une image peut vouloir diffuser plus d’images à l’avenir. On peut donc affirmer que l’écriture d’un serveur de fichiers statique spécifique ne pouvant contenir qu’un seul fichier avec un chemin codé est un peu myope. Il semble difficile d’imaginer que quiconque recherche une réponse sur la façon de servir une image se contente d’une solution qui ne sert qu’une seule image au lieu d’une solution générale pour servir une image.

En bref, la question est de savoir comment servir une image et une réponse à cela est d’utiliser un module approprié pour le faire de manière sécurisée, préformée et fiable , lisible, maintenable et pérenne, tout en utilisant les meilleures pratiques des nœuds professionnels. développement. Mais je suis d’accord pour dire qu’un excellent ajout à une telle solution serait de montrer un moyen d’implémenter les mêmes fonctionnalités manuellement, mais malheureusement, toutes les tentatives pour y parvenir ont échoué jusqu’à présent. Et c’est pourquoi j’ai écrit de nouveaux exemples.

Après cette courte introduction, voici mes cinq exemples faisant le travail sur 5 niveaux d’abstraction différents.

Fonctionnalité minimale

Chaque exemple sert des fichiers du répertoire public et prend en charge la fonctionnalité minimale de:

  • Types MIME pour les fichiers les plus courants
  • sert HTML, JS, CSS, texte brut et images
  • sert index.html comme index de répertoire par défaut
  • répond avec des codes d’erreur pour les fichiers manquants
  • aucune vulnérabilité de traversée de chemin
  • pas de conditions de course lors de la lecture de fichiers

J’ai testé chaque version sur les versions Node 4, 5, 6 et 7.

express.static

Cette version utilise le express.static intégré express.static du module express .

Cet exemple a le plus de fonctionnalités et le moins de code.

 var path = require('path'); var express = require('express'); var app = express(); var dir = path.join(__dirname, 'public'); app.use(express.static(dir)); app.listen(3000, function () { console.log('Listening on http://localhost:3000/'); }); 

express

Cette version utilise le module express mais sans le middleware express.static . Servir des fichiers statiques est implémenté en tant que gestionnaire de routage unique à l’aide de stream.

Cet exemple a des contre-mesures de parcours simples et prend en charge un ensemble limité de types MIME les plus courants.

 var path = require('path'); var express = require('express'); var app = express(); var fs = require('fs'); var dir = path.join(__dirname, 'public'); var mime = { html: 'text/html', txt: 'text/plain', css: 'text/css', gif: 'image/gif', jpg: 'image/jpeg', png: 'image/png', svg: 'image/svg+xml', js: 'application/javascript' }; app.get('*', function (req, res) { var file = path.join(dir, req.path.replace(/\/$/, '/index.html')); if (file.indexOf(dir + path.sep) !== 0) { return res.status(403).end('Forbidden'); } var type = mime[path.extname(file).slice(1)] || 'text/plain'; var s = fs.createReadStream(file); s.on('open', function () { res.set('Content-Type', type); s.pipe(res); }); s.on('error', function () { res.set('Content-Type', 'text/plain'); res.status(404).end('Not found'); }); }); app.listen(3000, function () { console.log('Listening on http://localhost:3000/'); }); 

connect

Cette version utilise le module de connect qui est un niveau d’abstraction inférieur à express .

Cet exemple a des fonctionnalités similaires à la version express mais utilise des API à levier légèrement inférieur.

 var path = require('path'); var connect = require('connect'); var app = connect(); var fs = require('fs'); var dir = path.join(__dirname, 'public'); var mime = { html: 'text/html', txt: 'text/plain', css: 'text/css', gif: 'image/gif', jpg: 'image/jpeg', png: 'image/png', svg: 'image/svg+xml', js: 'application/javascript' }; app.use(function (req, res) { var reqpath = req.url.toSsortingng().split('?')[0]; if (req.method !== 'GET') { res.statusCode = 501; res.setHeader('Content-Type', 'text/plain'); return res.end('Method not implemented'); } var file = path.join(dir, reqpath.replace(/\/$/, '/index.html')); if (file.indexOf(dir + path.sep) !== 0) { res.statusCode = 403; res.setHeader('Content-Type', 'text/plain'); return res.end('Forbidden'); } var type = mime[path.extname(file).slice(1)] || 'text/plain'; var s = fs.createReadStream(file); s.on('open', function () { res.setHeader('Content-Type', type); s.pipe(res); }); s.on('error', function () { res.setHeader('Content-Type', 'text/plain'); res.statusCode = 404; res.end('Not found'); }); }); app.listen(3000, function () { console.log('Listening on http://localhost:3000/'); }); 

http

Cette version utilise le module http qui est l’API de plus bas niveau pour HTTP dans Node.

Cet exemple a des fonctionnalités similaires à la version de connect mais utilise encore plus d’API de niveau inférieur.

 var path = require('path'); var http = require('http'); var fs = require('fs'); var dir = path.join(__dirname, 'public'); var mime = { html: 'text/html', txt: 'text/plain', css: 'text/css', gif: 'image/gif', jpg: 'image/jpeg', png: 'image/png', svg: 'image/svg+xml', js: 'application/javascript' }; var server = http.createServer(function (req, res) { var reqpath = req.url.toSsortingng().split('?')[0]; if (req.method !== 'GET') { res.statusCode = 501; res.setHeader('Content-Type', 'text/plain'); return res.end('Method not implemented'); } var file = path.join(dir, reqpath.replace(/\/$/, '/index.html')); if (file.indexOf(dir + path.sep) !== 0) { res.statusCode = 403; res.setHeader('Content-Type', 'text/plain'); return res.end('Forbidden'); } var type = mime[path.extname(file).slice(1)] || 'text/plain'; var s = fs.createReadStream(file); s.on('open', function () { res.setHeader('Content-Type', type); s.pipe(res); }); s.on('error', function () { res.setHeader('Content-Type', 'text/plain'); res.statusCode = 404; res.end('Not found'); }); }); server.listen(3000, function () { console.log('Listening on http://localhost:3000/'); }); 

net

Cette version utilise le module net qui est l’API de niveau le plus bas pour les sockets TCP dans Node.

Cet exemple présente certaines des fonctionnalités de la version http , mais le protocole HTTP minimal et incomplet a été implémenté à partir de zéro. Comme il ne prend pas en charge le codage par blocs, il charge les fichiers en mémoire avant de les servir pour connaître la taille avant d’envoyer une réponse, car la mise en attente des fichiers et leur chargement introduiraient une condition de concurrence.

 var path = require('path'); var net = require('net'); var fs = require('fs'); var dir = path.join(__dirname, 'public'); var mime = { html: 'text/html', txt: 'text/plain', css: 'text/css', gif: 'image/gif', jpg: 'image/jpeg', png: 'image/png', svg: 'image/svg+xml', js: 'application/javascript' }; var server = net.createServer(function (con) { var input = ''; con.on('data', function (data) { input += data; if (input.match(/\n\r?\n\r?/)) { var line = input.split(/\n/)[0].split(' '); var method = line[0], url = line[1], pro = line[2]; var reqpath = url.toSsortingng().split('?')[0]; if (method !== 'GET') { var body = 'Method not implemented'; con.write('HTTP/1.1 501 Not Implemented\n'); con.write('Content-Type: text/plain\n'); con.write('Content-Length: '+body.length+'\n\n'); con.write(body); con.destroy(); return; } var file = path.join(dir, reqpath.replace(/\/$/, '/index.html')); if (file.indexOf(dir + path.sep) !== 0) { var body = 'Forbidden'; con.write('HTTP/1.1 403 Forbidden\n'); con.write('Content-Type: text/plain\n'); con.write('Content-Length: '+body.length+'\n\n'); con.write(body); con.destroy(); return; } var type = mime[path.extname(file).slice(1)] || 'text/plain'; var s = fs.readFile(file, function (err, data) { if (err) { var body = 'Not Found'; con.write('HTTP/1.1 404 Not Found\n'); con.write('Content-Type: text/plain\n'); con.write('Content-Length: '+body.length+'\n\n'); con.write(body); con.destroy(); } else { con.write('HTTP/1.1 200 OK\n'); con.write('Content-Type: '+type+'\n'); con.write('Content-Length: '+data.byteLength+'\n\n'); con.write(data); con.destroy(); } }); } }); }); server.listen(3000, function () { console.log('Listening on http://localhost:3000/'); }); 

Télécharger des exemples

J’ai posté tous les exemples sur GitHub avec plus d’explications.

Exemples avec express.static , express , connect , http et net :

Autre projet utilisant uniquement express.static :

Des tests

Les résultats des tests sont disponibles sur Travis:

Tout est testé sur les versions de nœud 4, 5, 6 et 7.

Voir également

Autres réponses connexes:

  • Échec du chargement de la ressource du même répertoire lors de la redirection de Javascript
  • onload js appel ne fonctionne pas avec le noeud
  • Envoi de contenu de dossier entier au client avec express
  • Le chargement des partiels échoue sur le serveur JS
  • Nœud JS ne desservant pas l’image statique

Vous devez utiliser le cadre express .

npm install express

 var express = require('express'); var app = express(); app.use(express.static(__dirname + '/public')); app.listen(8080); 

et ensuite l’url localhost: 8080 / images / logo.gif devrait fonctionner

J’aime utiliser Restify pour les services REST. Dans mon cas, j’avais créé un service REST pour servir des images, puis si une source d’image renvoyait 404/403, je voulais renvoyer une autre image. Voici ce que j’ai imaginé en combinant certaines choses ici:

 function processRequest(req, res, next, url) { var httpOptions = { hostname: host, path: url, port: port, method: 'GET' }; var reqGet = http.request(httpOptions, function (response) { var statusCode = response.statusCode; // Many images come back as 404/403 so check explicitly if (statusCode === 404 || statusCode === 403) { // Send default image if error var file = 'img/user.png'; fs.stat(file, function (err, stat) { var img = fs.readFileSync(file); res.contentType = 'image/png'; res.contentLength = stat.size; res.end(img, 'binary'); }); } else { var idx = 0; var len = parseInt(response.header("Content-Length")); var body = new Buffer(len); response.setEncoding('binary'); response.on('data', function (chunk) { body.write(chunk, idx, "binary"); idx += chunk.length; }); response.on('end', function () { res.contentType = 'image/jpg'; res.send(body); }); } }); reqGet.on('error', function (e) { // Send default image if error var file = 'img/user.png'; fs.stat(file, function (err, stat) { var img = fs.readFileSync(file); res.contentType = 'image/png'; res.contentLength = stat.size; res.end(img, 'binary'); }); }); reqGet.end(); return next(); } 

Version nœud vanille comme demandé:

 var http = require('http'); var url = require('url'); var path = require('path'); var fs = require('fs'); http.createServer(function(req, res) { // parse url var request = url.parse(req.url, true); var action = request.pathname; // disallow non get requests if (req.method !== 'GET') { res.writeHead(405, {'Content-Type': 'text/plain' }); res.end('405 Method Not Allowed'); return; } // routes if (action === '/') { res.writeHead(200, {'Content-Type': 'text/plain' }); res.end('Hello World \n'); return; } // static (note not safe, use a module for anything serious) var filePath = path.join(__dirname, action).split('%20').join(' '); fs.exists(filePath, function (exists) { if (!exists) { // 404 missing files res.writeHead(404, {'Content-Type': 'text/plain' }); res.end('404 Not Found'); return; } // set the content type var ext = path.extname(action); var contentType = 'text/plain'; if (ext === '.gif') { contentType = 'image/gif' } res.writeHead(200, {'Content-Type': contentType }); // stream the file fs.createReadStream(filePath, 'utf-8').pipe(res); }); }).listen(8080, '127.0.0.1'); 

Il est trop tard mais aide quelqu’un, j’utilise la node version v7.9.0 et express version 4.15.0

si votre structure de répertoire est quelque chose comme ça:

 your-project uploads package.json server.js 

code server.js:

 var express = require('express'); var app = express(); app.use(express.static(__dirname + '/uploads'));// you can access image //using this url: http://localhost:7000/abc.jpg //make sure `abc.jpg` is present in `uploads` dir. //Or you can change the directory for hiding real directory name: `app.use('/images', express.static(__dirname+'/uploads/'));// you can access image using this url: http://localhost:7000/images/abc.jpg app.listen(7000); 

Vous devez utiliser une bibliothèque compatible avec les URL et les fichiers statiques. Je recommande d’utiliser Express . Il possède des fonctionnalités pour la configuration des routes et un module de service de fichiers statiques.

Tout d’abord, vous devez installer un package express par npm . Vous pouvez l’installer en utilisant npm i express .

Une fois le module express installé, spécifiez le code suivant dans votre fichier:

const express = require('express'); const app = express(); app.use(express.static('public/images'));

 var http = require('http'); var fs = require('fs'); http.createServer(function(req, res) { res.writeHead(200,{'content-type':'image/jpg'}); fs.createReadStream('./image/demo.jpg').pipe(res); }).listen(3000); console.log('server running at 3000');