Cómo servir una imagen usando nodejs

Tengo un logotipo que reside en public / images / logo.gif. Aquí está mi código nodejs.

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

Funciona, pero cuando solicito localhost: 8080 / logo.gif entonces obviamente no obtengo el logo.

Qué cambios necesito hacer para servir una imagen.

Estoy de acuerdo con los otros carteles que eventualmente, deberían usar un marco, como Express … pero primero también deberían entender cómo hacer algo fundamental como esto sin una biblioteca, para entender realmente lo que la biblioteca extrae para ustedes. los pasos son

  1. Analizar la solicitud HTTP entrante para ver qué ruta solicita el usuario
  2. Agregue una vía en la statement condicional para que el servidor responda
  3. Si se solicita la imagen, lea el archivo de imagen del disco.
  4. Sirve el tipo de contenido de la imagen en un encabezado
  5. Sirve los contenidos de la imagen en el cuerpo

El código se vería así (no probado)

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

Actualización 2016

Ejemplos con Express y sin Express que realmente funcionan

Esta pregunta tiene más de 5 años pero cada respuesta tiene algunos problemas .

TL; DR

Desplácese hacia abajo para ver ejemplos para servir una imagen con:

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

Todos los ejemplos también están en GitHub: https://github.com/rsp/node-static-http-servers

Los resultados de las pruebas están disponibles en Travis: https://travis-ci.org/rsp/node-static-http-servers

Introducción

Después de más de 5 años desde que se formuló esta pregunta, solo hay una respuesta correcta por generalhenry, pero aunque esa respuesta no tiene problemas con el código, parece que tiene algunos problemas con la recepción . Se comentó que “no explica mucho más que cómo confiar en alguien más para hacer el trabajo” y el hecho de cuántas personas han votado este comentario muestra claramente que muchas cosas necesitan aclaración.

En primer lugar, una buena respuesta a “Cómo servir imágenes usando Node.js” no es implementar un servidor de archivos estático desde cero y hacerlo mal. Una buena respuesta es usar un módulo como Express que hace el trabajo correctamente .

Respondiendo a los comentarios que dicen que usar Express “no explica mucho más que cómo confiar en otra persona para hacer el trabajo” debe señalarse, que el uso del módulo http ya depende de otra persona para hacer el trabajo. Si alguien no quiere confiar en nadie para hacer el trabajo, al menos debería usar sockets TCP sin procesar, lo cual hago en uno de mis ejemplos a continuación.

Un problema más serio es que todas las respuestas aquí que usan el módulo http están rotas . Introducen condiciones de carrera , resolución de ruta insegura que conducirá a la vulnerabilidad de cruce de ruta , locking de E / S que fallará por completo al atender cualquier solicitud concurrente y otros problemas sutiles; están completamente rotos como ejemplos de lo que la pregunta plantea, y sin embargo, ya usan la abstracción proporcionada por el módulo http lugar de usar sockets TCP, por lo que ni siquiera hacen todo desde cero, como afirman.

Si la pregunta era “Cómo implementar un servidor de archivos estáticos desde cero, como un ejercicio de aprendizaje”, entonces, por supuesto, las respuestas sobre cómo hacerlo deberían publicarse, pero incluso entonces deberíamos esperar que al menos sean correctas . Además, no es descabellado suponer que alguien que quiera publicar una imagen desee enviar más imágenes en el futuro, por lo que podría argumentarse que escribir un servidor de archivos estáticos personalizado específico que pueda servir solo un único archivo con una ruta codificada es algo miope. Parece difícil imaginar que cualquiera que busque una respuesta sobre cómo publicar una imagen se contentaría con una solución que sirva solo una imagen en lugar de una solución general para publicar cualquier imagen.

En resumen, la pregunta es cómo servir una imagen y una respuesta a eso es usar un módulo apropiado para hacer eso de una manera segura, preformada y confiable que sea legible, mantenible y preparada para el futuro mientras se usa la mejor práctica del nodo profesional. desarrollo. Pero estoy de acuerdo en que una gran adición a esa respuesta sería mostrar una forma de implementar la misma funcionalidad de forma manual, pero lamentablemente cada bash de hacerlo ha fallado hasta el momento. Y es por eso que escribí algunos ejemplos nuevos.

Después de esta breve introducción, aquí están mis cinco ejemplos haciendo el trabajo en 5 niveles diferentes de abstracción.

Funcionalidad mínima

Cada ejemplo sirve archivos del directorio public y admite la funcionalidad mínima de:

  • Tipos MIME para la mayoría de los archivos comunes
  • sirve HTML, JS, CSS, texto plano e imágenes
  • sirve index.html como un índice de directorio predeterminado
  • responde con códigos de error para archivos perdidos
  • sin vulnerabilidades de recorrido cruzado
  • no hay condiciones de carrera mientras lee archivos

Probé todas las versiones en Node versiones 4, 5, 6 y 7.

express.static

Esta versión usa el middleware express.static incorporado del módulo express .

Este ejemplo tiene la mayor funcionalidad y la menor cantidad de código.

 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

Esta versión usa el módulo express pero sin el middleware express.static . La publicación de archivos estáticos se implementa como un manejador de ruta único que utiliza transmisiones.

Este ejemplo tiene contramedidas de recorrido cruzado simples y admite un conjunto limitado de tipos MIME más comunes.

 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

Esta versión usa el módulo de connect que es un nivel de abstracción menor que el express .

Este ejemplo tiene una funcionalidad similar a la versión express , pero usa API de palanca levemente inferior.

 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

Esta versión usa el módulo http que es la API de nivel más bajo para HTTP en Node.

Este ejemplo tiene una funcionalidad similar a la versión de connect , pero usa aún más API de nivel inferior.

 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

Esta versión usa el módulo de net que es la API de nivel más bajo para sockets TCP en el nodo.

Este ejemplo tiene algunas de las funcionalidades de la versión http , pero el protocolo HTTP mínimo e incompleto se ha implementado desde cero. Dado que no es compatible con la encoding fragmentada, carga los archivos en la memoria antes de servirlos para conocer el tamaño antes de enviar una respuesta porque al estampar los archivos y luego cargarlos se introduciría una condición de carrera.

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

Descargue ejemplos

Publiqué todos los ejemplos en GitHub con más explicaciones.

Ejemplos con express.static , express , connect , http y net :

Otro proyecto usando solo express.static :

Pruebas

Los resultados de las pruebas están disponibles en Travis:

Todo se prueba en las versiones de nodo 4, 5, 6 y 7.

Ver también

Otras respuestas relacionadas:

  • Error al cargar recursos del mismo directorio al redirigir Javascript
  • onload js call no funciona con nodo
  • Enviar todo el contenido de la carpeta al cliente con Express
  • La carga de parciales falla en el servidor JS
  • El nodo JS no sirve la imagen estática

Deberías usar el marco express .

npm install express

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

y luego la url localhost: 8080 / images / logo.gif debería funcionar

Me gusta usar Restify para servicios REST. En mi caso, había creado un servicio REST para mostrar imágenes y luego, si una fuente de imagen arrojaba 404/403, quería devolver una imagen alternativa. Esto es lo que se me ocurrió al combinar algunas de las cosas aquí:

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

Versión del nodo de Vainilla según lo solicitado:

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

Ya es demasiado tarde pero ayuda a alguien, estoy usando la node version v7.9.0 y la express version 4.15.0

si su estructura de directorios es algo como esto:

 your-project uploads package.json server.js 

código 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); 

Necesita usar una biblioteca que tenga conocimiento de las URL y los archivos estáticos. Recomiendo usar Express . Tiene instalaciones para configurar rutas y un módulo de servicio de archivos estáticos.

Primero, necesita instalar un paquete express por npm . Puedes instalarlo usando npm i express .

Una vez que haya instalado el módulo express, especifique el siguiente código en su archivo:

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