Node.js, Express ve Mongoose kullanarak görüntü yükleme


102

Yıllar geçtikçe işler değiştiğinden, lütfen daha güncel bilgilere sahip yeni yanıtları düşünün!

Pek çok yeni Node.js kitaplığı hızlı bir şekilde eski haline getirildiğinden ve göreli olarak birkaç örnek olduğundan, görüntüleri yükleme hakkında şunu kullanarak sormak istiyorum:

  • Node.js (v0.4.1)
  • Ekspres (1.0.7)
  • Firavun Faresi (1.1.0).

Başkaları bunu nasıl yaptı?

Buldum : node-formidable , ancak genel olarak resim yüklemede yeniyim, bu nedenle genel şeyleri ve bunu yapmanın yollarını Node.js ve Express kullanarak öğrenmek istiyorum.


12
Güncelle Express'in daha yeni sürümlerinde bu işlevsellik yerleşik olarak bulunmaktadır, 'connect-form' ile vakit geçirmeden önce bunu göz önünde bulundurun
user531694

4
2015 tl; sunucunuza çok parçalı / form isteklerini dr gönderin ve BodyParser artık dosyaları ayrıştırmadığı için bunları Multer ile ayrıştırın. npm install multer --saveve sonra uygulamanızda erişebileceğiniz req.files.your_file_param_nameve biriyle s3 kaydetmek aws-sdkveyafs.writeFile(...)
kullanıcı

Yanıtlar:


74

İlk kez kendi sorumu cevaplayacağım. Doğrudan kaynaktan bir örnek buldum. Lütfen zayıf girintiyi affedin. Kopyalarken ve yapıştırırken nasıl düzgün girinti yapacağımdan emin değildim. Kod doğrudan GitHub'daki Express multipart/form-dataörneğinden gelir .

// 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('<form method="post" enctype="multipart/form-data">'
    + '<p>Image: <input type="file" name="image" /></p>'
    + '<p><input type="submit" value="Upload" /></p>'
    + '</form>');
});

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

3
Evet ama dosyayı nasıl kaydediyorsun?
Nick Retallack

1
@NickRetallack Kaydedilen dosya files.image.path adresinde saklanır
Robin Duckett

@ robin-duckett, önceden dosya adını ve yolunu nasıl belirlersiniz?
Luc

4
@Luc: Yapmazsınız, başka bir yere taşıdığınız geçici bir dizine kaydedilir.
kevmo314

1
Ekspres: // 'de yükleme dizinini bu şekilde yapılandırırsınız. NOT: alt modüllerde sorunları önlemek için yükleme dizinine giden mutlak bir yol kullanın! // app.use (express.bodyParser ({uploadDir: uploadDir}));
Risadinha

47

Ekspres kullandığınız için bodyParser eklemeniz yeterlidir:

app.use(express.bodyParser());

ardından rotanız req.files içindeki yüklenen dosyalara otomatik olarak erişebilir:

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

Giriş denetimini şöyle adlandırırsanız (Jade'de):

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

Ardından, 'files.todo' içindeki yolu ve orijinal dosya adını aldığınızda yüklenen dosya hazırdır:

  • req.files.todo.path ve
  • req.files.todo.name

diğer yararlı req.files özellikleri:

  • boyut (bayt cinsinden)
  • tür (örneğin, 'resim / png')
  • lastModifiedate
  • _writeStream.encoding (ör. 'ikili')

Bunun böyle olduğunu hiç duymadım ve devam edip bu adamların en iyi developer.mozilla.org/en-US/docs/JavaScript/Guide/… bildiklerini söyleyeceğim, bu yüzden ikimiz de yanılıyoruz;)
srquinn

bodyParsergüvensizdir, en azından şuna göre: andrewkelley.me/post/do-not-use-bodyparser-with-express-js.html . Jon J'nin cevabı benim için çalıştı.
Matt Browne

"Güvensiz" derken, bu sadece geçici dosyaların oluşturulduğu anlamına gelir, böylece bir "saldırı" sunucunun disk alanını muhtemelen geçici dosyalarla doldurabilir. Bu bir güvenlik açığı olmadığı için daha sağlam bir konudur.
Brent Faust

19

Connect body ayrıştırıcı ara yazılımını ana uygulama dosyanızdaki bir yapılandırma bloğunda yapılandırabilirsiniz:

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

Sanırım yüklemeleri halletmenin en iyi yolu bu. Dosyayı, ayrı bir konuma kopyalamak yerine yalnızca silmek istiyorsanız saklayın. Teşekkürler.
Eastern Monk

2
@AksharPrabhuDesai Evet ve hayır. Bir fotoğraf yükleme / kırpma aracınız olduğunu varsayalım. Kullanıcının doğrudan ortak klasörünüze yüklemesine izin verirseniz, ciddi bir güvenlik açığınız vardır. Bu durumda, en iyisi bir tmp klasörüne yüklemek ve ardından dosyanın Truva atı olmadığını onayladıktan sonra ortak klasörünüze taşımaktır.
srquinn

Artık desteklenmiyor gibi görünüyor. Güzel bir çözüm gibi görünüyordu.
Blaze

14

Gördüğünüz gibi, yapabileceğiniz en iyi şey, görüntüyü diske yüklemek ve URL'yi MongoDB'ye kaydetmek. Görüntüyü tekrar aldığınızda dinlenin. Sadece URL'yi belirtin ve bir resim alacaksınız. Yükleme kodu aşağıdaki gibidir.

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

Şimdi hedef yolu MongoDB veritabanınıza kaydedin.

Yine, görüntüyü alırken, URL'yi MongoDB veritabanından çıkarın ve bu yöntemde kullanın.

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

9

Bu kodu deneyin, yardımcı olacaktır.

app.get('/photos/new', function(req, res){
  res.send('<form method="post" enctype="multipart/form-data">'
    + '<p>Data: <input type="filename" name="filename" /></p>'
    + '<p>file: <input type="file" name="file" /></p>'
    + '<p><input type="submit" value="Upload" /></p>'
    + '</form>');
});


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

util.pump(ins, ous)amortismana tabi tutulursa, bu ins.pipe(ous);şimdi yapılabilir . Ancak bu, eski konumdaki görüntü dosyasını kaldıracak mı?
Emiel Vandenbussche

8

Dosyayı kaydedeceği yolu ayarlamak için aşağıdakileri de kullanabilirsiniz.

req.form.uploadDir = "<path>";


2

Yine bodyParser'ı kullanmak istemiyorsanız, aşağıdakiler çalışır:

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

2

Express 3.0 için, zorlu olayları kullanmak istiyorsanız, çok parçalı ara yazılımı kaldırmanız gerekir, böylece yeni bir örneğini oluşturabilirsiniz.

Bunu yapmak için:

app.use(express.bodyParser());

Şu şekilde yazılabilir:

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

Ve şimdi form nesnesini oluşturun:

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

Bunu blogumda da yayınladım , Yükleme sırasında Express 3.0'da müthiş form nesnesi alma .


Öneriniz yanlış yönlendiriyor, bodyParser temelde formu ayrıştırıyor. ve müthiş yapılandırma değişkenlerini kabul eder.
Marius

1
@timoxley bu sadece örnek
Risto Novik

1

Orijinal sorunun belirli sürümlerle ilgili olduğunu biliyorum, ancak aynı zamanda "en son" - @ JohnAllen'in gönderisine de atıfta bulunuluyor - Expressjs bodyParser ve bağlantı formu nedeniyle artık alakalı değil

Bu, kullanımı kolay yerleşik bodyParser () yöntemini gösterir:

 /**
 * 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('<form method="post" enctype="multipart/form-data">'
    + '<p>Image: <input type="file" name="image" /></p>'
    + '<p><input type="submit" value="Upload" /></p>'
    + '</form>');
});

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

0

Birden çok dosya yükleme yöntemim var:

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

Formunuzun enctype = "multipart / form-data" içerdiğinden emin olun

Umarım bu size yardımcı olur;)


0

İşte, Express'in sonraki sürümlerinde bodyParser'a göre tavsiye edilen müthiş paketi kullanarak resimlerinizi yüklemenin bir yolu. Bu aynı zamanda resimlerinizi anında yeniden boyutlandırma yeteneğini de içerir:

Web sitemden: Node.js ve Express ile Görüntüleri Yükleme ve Yeniden Boyutlandırma (anında) .

İşte özü:

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 = '<form action="/upload" enctype="multipart/form-data" method="post">'+ '<input name="title" type="text" />
  '+ '<input multiple="multiple" name="upload" type="file" />
  '+ '<input type="submit" value="Upload" />'+ '</form>';
  res.end(form); 
}); 
app.listen(8080);

NOT: Başparmağın hızlı şekilde yeniden boyutlandırılması için Image Magick gerekir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.