Upload de imagens usando Node.js, Express e Mongoose

Por favor, considere respostas mais recentes que tenham informações mais atualizadas, já que as coisas mudaram ao longo dos anos!

Como muitas novas bibliotecas do Node.js estão sendo rapidamente obsoletas e há relativamente poucos exemplos, gostaria de perguntar sobre o upload de imagens usando as versões mais recentes do Node.js (v0.4.1), Express (1.0.7) e Mongoose ( 1.1.0). Como os outros fizeram isso?

Eu encontrei: https://github.com/felixge/node-formidable , mas eu sou novo para o upload de imagens em geral, então eu quero aprender coisas gerais e maneiras de fazê-lo usando Node.js e Express.

Eu responderei minha própria pergunta pela primeira vez. Eu encontrei um exemplo direto da fonte. Por favor, perdoe o recuo pobre. Eu não tinha certeza de como recuar corretamente ao copiar e colar. O código vem direto do exemplo Express multipart/form-data no GitHub.

 // Expose modules in ./support for demo purposes require.paths.unshift(__dirname + '/../../support'); /** * Module dependencies. */ var express = require('../../lib/express') , form = require('connect-form'); var app = express.createServer( // connect-form (http://github.com/visionmedia/connect-form) // middleware uses the formidable middleware to parse urlencoded // and multipart form data form({ keepExtensions: true }) ); app.get('/', function(req, res){ res.send('
' + '

Image:

' + '

' + '
'); }); app.post('/', function(req, res, next){ // connect-form adds the req.form object // we can (optionally) define onComplete, passing // the exception (if any) fields parsed, and files parsed req.form.complete(function(err, fields, files){ if (err) { next(err); } else { console.log('\nuploaded %s to %s' , files.image.filename , files.image.path); res.redirect('back'); } }); // We can add listeners for several form // events such as "progress" req.form.on('progress', function(bytesReceived, bytesExpected){ var percent = (bytesReceived / bytesExpected * 100) | 0; process.stdout.write('Uploading: %' + percent + '\r'); }); }); app.listen(3000); console.log('Express app started on port 3000');

Desde que você está usando express, basta adicionar bodyParser:

 app.use(express.bodyParser()); 

então sua rota automaticamente tem access ao (s) arquivo (s) carregado (s) em req.files:

 app.post('/todo/create', function (req, res) { // TODO: move and rename the file using req.files.path & .name) res.send(console.dir(req.files)); // DEBUG: display available fields }); 

Se você nomear o controle de input “todo” assim (em Jade):

 form(action="/todo/create", method="POST", enctype="multipart/form-data") input(type='file', name='todo') button(type='submit') New 

Em seguida, o arquivo carregado está pronto no momento em que você obtém o caminho e o nome do arquivo original em ‘files.todo’:

  • req.files.todo.path e
  • req.files.todo.name

outras propriedades úteis do req.files:

  • tamanho (em bytes)
  • tipo (por exemplo, ‘image / png’)
  • lastModifiedate
  • _writeStream.encoding (por exemplo, ‘binário’)

Você pode configurar o middleware do analisador de corpo de conexão em um bloco de configuração no arquivo principal do aplicativo:

  /** Form Handling */ app.use(express.bodyParser({ uploadDir: '/tmp/uploads', keepExtensions: true })) app.use(express.limit('5mb')); 

Veja, a melhor coisa que você pode fazer é apenas fazer o upload da imagem para o disco e salvar o URL no MongoDB. rest quando você recuperar a imagem novamente. Basta especificar o URL e você receberá uma imagem. O código para o upload é o seguinte.

 app.post('/upload', function(req, res) { // Get the temporary location of the file var tmp_path = req.files.thumbnail.path; // Set where the file should actually exists - in this case it is in the "images" directory. target_path = '/tmp/' + req.files.thumbnail.name; // Move the file from the temporary location to the intended location fs.rename(tmp_path, target_path, function(err) { if (err) throw err; // Delete the temporary file, so that the explicitly set temporary upload dir does not get filled with unwanted files. fs.unlink(tmp_path, function() { if (err) throw err; // }); }); }); 

Agora salve o caminho de destino no database do MongoDB.

Novamente, ao recuperar a imagem, basta extrair a URL do database MongoDB e usá-la nesse método.

 fs.readFile(target_path, "binary", function(error, file) { if(error) { res.writeHead(500, {"Content-Type": "text/plain"}); res.write(error + "\n"); res.end(); } else { res.writeHead(200, {"Content-Type": "image/png"}); res.write(file, "binary"); } }); 

Tente este código. Ajudará.

 app.get('/photos/new', function(req, res){ res.send('
' + '

Data:

' + '

file:

' + '

' + '
'); }); app.post('/photos/new', function(req, res) { req.form.complete(function(err, fields, files) { if(err) { next(err); } else { ins = fs.createReadStream(files.photo.path); ous = fs.createWriteStream(__dirname + '/directory were u want to store image/' + files.photo.filename); util.pump(ins, ous, function(err) { if(err) { next(err); } else { res.redirect('/photos'); } }); //console.log('\nUploaded %s to %s', files.photo.filename, files.photo.path); //res.send('Uploaded ' + files.photo.filename + ' to ' + files.photo.path); } }); }); if (!module.parent) { app.listen(8000); console.log("Express server listening on port %d, log on to http://127.0.0.1:8000", app.address().port); }

Você também pode usar o seguinte para definir um caminho onde ele salva o arquivo.

 req.form.uploadDir = ""; 

Eu criei um exemplo que usa Express e Multer. É muito simples e evita todos os avisos do Connect

Pode ajudar alguém.

Novamente, se você não quiser usar o bodyParser, o seguinte funciona:

 var express = require('express'); var http = require('http'); var app = express(); app.use(express.static('./public')); app.configure(function(){ app.use(express.methodOverride()); app.use(express.multipart({ uploadDir: './uploads', keepExtensions: true })); }); app.use(app.router); app.get('/upload', function(req, res){ // Render page with upload form res.render('upload'); }); app.post('/upload', function(req, res){ // Returns json of uploaded file res.json(req.files); }); http.createServer(app).listen(3000, function() { console.log('App started'); }); 

Para o Express 3.0, se você quiser usar os events formidáveis, deve remover o middleware multipartes para criar a nova instância dele.

Para fazer isso:

 app.use(express.bodyParser()); 

Pode ser escrito como:

 app.use(express.json()); app.use(express.urlencoded()); app.use(express.multipart()); // Remove this line 

E agora crie o object de formulário:

 exports.upload = function(req, res) { var form = new formidable.IncomingForm; form.keepExtensions = true; form.uploadDir = 'tmp/'; form.parse(req, function(err, fields, files){ if (err) return res.end('You found error'); // Do something with files.image etc console.log(files.image); }); form.on('progress', function(bytesReceived, bytesExpected) { console.log(bytesReceived + ' ' + bytesExpected); }); form.on('error', function(err) { res.writeHead(400, {'content-type': 'text/plain'}); // 400: Bad Request res.end('error:\n\n'+util.inspect(err)); }); res.end('Done'); return; }; 

Eu também postei isso no meu blog, Obtendo form form form object no Express 3.0 no upload .

Eu sei que a pergunta original relacionada a versões específicas, mas também se referia ao “mais recente” – a postagem de @JohnAllen não é mais relevante devido ao bodyParser do Expressjs e ao formulário de conexão

Isso demonstra o bodyParser () embutido e fácil de usar:

  /** * Module dependencies. */ var express = require('express') var app = express() app.use(express.bodyParser({ keepExtensions: true, uploadDir: '/home/svn/rest-api/uploaded' })) app.get('/', function(req, res){ res.send('
' + '

Image:

' + '

' + '
'); }); app.post('/', function(req, res, next){ res.send('Uploaded: ' + req.files.image.name) return next() }); app.listen(3000); console.log('Express app started on port 3000');

Aqui está uma maneira de carregar suas imagens usando o pacote formidable, que é recomendado sobre bodyParser em versões posteriores do Express. Isso também inclui a capacidade de resize suas imagens em tempo real:

Upload e Redimensionamento de Imagens (on the fly) Com Node.js e Express .

Aqui está a essência:

 var express = require("express"), app = express(), formidable = require('formidable'), util = require('util') fs = require('fs-extra'), qt = require('quickthumb'); // Use quickthumb app.use(qt.static(__dirname + '/')); app.post('/upload', function (req, res){ var form = new formidable.IncomingForm(); form.parse(req, function(err, fields, files) { res.writeHead(200, {'content-type': 'text/plain'}); res.write('received upload:\n\n'); res.end(util.inspect({fields: fields, files: files})); }); form.on('end', function(fields, files) { /* Temporary location of our uploaded file */ var temp_path = this.openedFiles[0].path; /* The file name of the uploaded file */ var file_name = this.openedFiles[0].name; /* Location where we want to copy the uploaded file */ var new_location = 'uploads/'; fs.copy(temp_path, new_location + file_name, function(err) { if (err) { console.error(err); } else { console.log("success!") } }); }); }); // Show the upload form app.get('/', function (req, res){ res.writeHead(200, {'Content-Type': 'text/html' }); /* Display the file upload form. */ form = '
'+ ' '+ ' '+ ''+ '
'; res.end(form); }); app.listen(8080);

NOTA: Isso requer Magia de Imagem para resize o polegar rapidamente.

Há o meu método para vários arquivos de upload:

Nodejs:

 router.post('/upload', function(req , res) { var multiparty = require('multiparty'); var form = new multiparty.Form(); var fs = require('fs'); form.parse(req, function(err, fields, files) { var imgArray = files.imatges; for (var i = 0; i < imgArray.length; i++) { var newPath = './public/uploads/'+fields.imgName+'/'; var singleImg = imgArray[i]; newPath+= singleImg.originalFilename; readAndWriteFile(singleImg, newPath); } res.send("File uploaded to: " + newPath); }); function readAndWriteFile(singleImg, newPath) { fs.readFile(singleImg.path , function(err,data) { fs.writeFile(newPath,data, function(err) { if (err) console.log('ERRRRRR!! :'+err); console.log('Fitxer: '+singleImg.originalFilename +' - '+ newPath); }) }) } }) 

Certifique-se de que seu formulário tenha enctype = "multipart / form-data"

Espero que isso lhe dê uma mão;)