Come servire un’immagine usando il nodojs

Ho un logo che risiede al pubblico / images / logo.gif. Ecco il mio codice nodejs.

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

Funziona ma quando richiedo il localhost: 8080 / logo.gif, ovviamente non ottengo il logo.

Quali cambiamenti devo fare per servire un’immagine.

Sono d’accordo con gli altri poster che alla fine, dovresti usare un framework, come Express .. ma prima dovresti anche capire come fare qualcosa di fondamentale come questo senza una libreria, per capire veramente cosa la biblioteca ti astragga per te .. i passi sono

  1. Analizza la richiesta HTTP in entrata, per vedere quale percorso l’utente sta chiedendo
  2. Aggiungi un percorso nell’istruzione condizionale per il server a cui rispondere
  3. Se l’immagine è richiesta, leggi il file immagine dal disco.
  4. Offri il tipo di contenuto dell’immagine in un’intestazione
  5. Serve i contenuti dell’immagine nel corpo

Il codice sarebbe simile a questo (non testato)

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

Aggiornamento 2016

Esempi con Express e senza Express che funzionano davvero

Questa domanda ha più di 5 anni ma ogni risposta ha qualche problema .

TL; DR

Scorri verso il basso gli esempi per servire un’immagine con:

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

Tutti gli esempi sono anche su GitHub: https://github.com/rsp/node-static-http-servers

I risultati dei test sono disponibili su Travis: https://travis-ci.org/rsp/node-static-http-servers

introduzione

Dopo oltre 5 anni da quando è stata posta questa domanda, c’è una sola risposta corretta da generalhenry ma anche se la risposta non ha problemi con il codice, sembra che abbia qualche problema con la ricezione . È stato detto che “non spiega molto altro da come fare affidamento su qualcun altro per portare a termine il lavoro” e il fatto che molte persone abbiano votato questo commento mostra chiaramente che molte cose necessitano di un chiarimento.

Prima di tutto, una buona risposta a “Come servire le immagini usando Node.js” non consiste nell’implementare un file server statico da zero e farlo male. Una buona risposta sta usando un modulo come Express che fa il lavoro correttamente .

Rispondendo ai commenti che dicono che l’uso di Express “non spiega molto altro da come fare affidamento su qualcun altro per portare a termine il lavoro” si deve notare che l’utilizzo del modulo http si basa già su qualcun altro per portare a termine il lavoro. Se qualcuno non vuole fare affidamento su nessuno per fare il lavoro, allora dovrebbero essere usati almeno socket TCP grezzi – cosa che faccio in uno dei miei esempi qui sotto.

Un problema più serio è che tutte le risposte qui che usano il modulo http sono infranti . Introducono condizioni di razza , una risoluzione del percorso insicura che porterà a una vulnerabilità del path traversal , bloccando l’I / O che fallirà completamente nel servire qualsiasi richiesta concomitante e altri problemi sottili – sono completamente infranti come esempi di ciò che la domanda pone, e tuttavia usano già l’astrazione fornita dal modulo http invece di utilizzare i socket TCP in modo da non fare nemmeno tutto da zero come affermano.

Se la domanda era “Come implementare il file server statico da zero, come un esercizio di apprendimento”, allora in ogni caso risponde come farlo dovrebbe essere pubblicato – ma anche allora dovremmo aspettarci che siano almeno corretti . Inoltre, non è irragionevole supporre che qualcuno che vuole servire un’immagine possa voler servire più immagini in futuro, quindi si potrebbe sostenere che la scrittura di un file server statico personalizzato specifico che può servire solo un singolo file con percorso hard-coded è un po ‘miope. Sembra difficile immaginare che chiunque cerchi una risposta su come servire un’immagine si accontenti di una soluzione che serve solo una singola immagine invece di una soluzione generale per servire qualsiasi immagine.

In breve, la domanda è come fornire un’immagine e una risposta è utilizzare un modulo appropriato per farlo in un modo sicuro, preformante e affidabile che sia leggibile, mantenibile e a prova di futuro mentre si utilizza la best practice del Nodo professionale. sviluppo. Ma sono d’accordo sul fatto che una grande aggiunta a una tale risposta sarebbe mostrare un modo per implementare la stessa funzionalità manualmente, ma purtroppo ogni tentativo di farlo non è riuscito finora. Ed è per questo che ho scritto alcuni nuovi esempi.

Dopo questa breve introduzione, ecco i miei cinque esempi che fanno il lavoro su 5 diversi livelli di astrazione.

Funzionalità minima

Ogni esempio serve i file dalla directory public e supporta le funzionalità minime di:

  • Tipi MIME per i file più comuni
  • serve HTML, JS, CSS, testo semplice e immagini
  • serve index.html come indice di directory predefinito
  • risponde con i codici di errore per i file mancanti
  • nessuna vulnerabilità di attraversamento del percorso
  • nessuna condizione di gara durante la lettura dei file

Ho testato ogni versione su Node versioni 4, 5, 6 e 7.

express.static

Questa versione utilizza il middleware incorporato express.static del modulo express .

Questo esempio ha il maggior numero di funzionalità e la minor quantità di codice.

 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

Questa versione utilizza il modulo express ma senza il middleware express.static . La pubblicazione di file statici viene implementata come un singolo gestore di route utilizzando gli stream.

Questo esempio ha semplici contromisure di attraversamento del percorso e supporta un insieme limitato di tipi MIME più comuni.

 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

Questa versione utilizza il modulo di connect che è un livello di astrazione inferiore a quello express .

Questo esempio ha funzionalità simili alla versione express ma utilizza API leggermente più basse.

 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.toString().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

Questa versione utilizza il modulo http che è l’API di livello più basso per HTTP nel nodo.

Questo esempio ha funzionalità simili alla versione di connect ma utilizza ancora più API di livello inferiore.

 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.toString().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

Questa versione utilizza il modulo net che è l’API di livello più basso per i socket TCP nel nodo.

Questo esempio ha alcune delle funzionalità della versione http ma il protocollo HTTP minimo e incompleto è stato implementato da zero. Poiché non supporta la codifica di Chunked, carica i file in memoria prima di servirli per conoscere la dimensione prima di inviare una risposta perché statting i file e quindi il caricamento introdurrebbe una condizione di competizione.

 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.toString().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/'); }); 

Scarica esempi

Ho pubblicato tutti gli esempi su GitHub con ulteriori spiegazioni.

Esempi con express.static , express , connect , http e net :

Altro progetto che utilizza solo express.static :

test

I risultati dei test sono disponibili su Travis:

Tutto è testato sulle versioni di Node 4, 5, 6 e 7.

Guarda anche

Altre risposte correlate:

  • Imansible caricare la risorsa dalla stessa directory durante il reindirizzamento di Javascript
  • onload js call che non funziona con il nodo
  • Invio di contenuto di cartelle intere al client con express
  • Caricamento parziali non riesce sul server JS
  • Nodo JS che non serve l’immagine statica

Dovresti usare la struttura espressa .

npm install express

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

e quindi l’url localhost: 8080 / images / logo.gif dovrebbe funzionare

Mi piace usare Restify per i servizi REST. Nel mio caso, avevo creato un servizio REST per servire le immagini e quindi se una sorgente di immagini restituiva 404/403, volevo restituire un’immagine alternativa. Ecco cosa mi è venuto in mente combinando alcune delle cose qui:

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

Versione del nodo vaniglia come richiesto:

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

È troppo tardi ma aiuta qualcuno, sto usando la node version v7.9.0 ed express version 4.15.0

se la struttura della tua directory è qualcosa del genere:

 your-project uploads package.json server.js 

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

È necessario utilizzare una libreria che è a conoscenza di URL e file statici. Raccomando l’uso di Express . Dispone di strutture per la configurazione di percorsi e un modulo di file serving statico.

Innanzitutto, è necessario installare un pacchetto express da npm . Puoi installarlo usando npm i express .

Una volta installato il modulo express, specifica il seguente codice nel tuo file:

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