Hochladen von Bildern mit Node.js, Express und Mongoose

102

Bitte berücksichtigen Sie neuere Antworten mit aktuelleren Informationen, da sich die Dinge im Laufe der Jahre geändert haben!

Da viele neue Node.js-Bibliotheken schnell veraltet sind und es sowieso relativ wenige Beispiele gibt, möchte ich nach dem Hochladen von Bildern fragen, indem ich:

  • Node.js (v0.4.1)
  • Express (1.0.7)
  • Mungo (1.1.0).

Wie haben andere das gemacht?

Ich habe festgestellt: Node-Formidable , aber ich bin neu im Hochladen von Bildern im Allgemeinen, daher möchte ich allgemeine Informationen und Möglichkeiten dazu mit Node.js und Express erlernen.

JohnAllen
quelle
12
Update Neuere Versionen von Express verfügen über diese integrierte Funktionalität.
Beachten Sie dies
4
Senden Sie mehrteilige / Formularanfragen an Ihren Server und analysieren Sie sie mit Multer, da BodyParser keine Dateien mehr analysiert. npm install multer --saveund dann in Ihrer App können Sie req.files.your_file_param_namemit aws-sdkoderfs.writeFile(...)
Benutzer

Antworten:

74

Ich werde zum ersten Mal meine eigene Frage beantworten. Ich habe ein Beispiel direkt aus der Quelle gefunden. Bitte vergib die schlechte Einkerbung. Ich war mir nicht sicher, wie ich beim Kopieren und Einfügen richtig einrücken sollte. Der Code stammt direkt aus dem Express- multipart/form-dataBeispiel auf 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('<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');
JohnAllen
quelle
3
Ja, aber wie speichert man die Datei?
Nick Retallack
1
@ NickRetallack Die gespeicherte Datei wird unter files.image.path gespeichert
Robin Duckett
@ robin-duckett, wie hast du den Dateinamen und den Pfad vorher angegeben?
Luc
4
@ Luc: Sie tun es nicht, es wird in einem temporären Verzeichnis gespeichert, aus dem Sie es an eine andere Stelle verschieben.
kevmo314
1
So konfigurieren Sie das Upload-Verzeichnis in express: // HINWEIS: Verwenden Sie einen absoluten Pfad zum Upload-Verzeichnis, um Probleme in Submodulen zu vermeiden! // app.use (express.bodyParser ({uploadDir: uploadDir}));
Risadinha
47

Da Sie Express verwenden, fügen Sie einfach bodyParser hinzu:

app.use(express.bodyParser());

dann hat Ihre Route automatisch Zugriff auf die hochgeladenen Dateien in 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
});

Wenn Sie das Eingabesteuerelement wie folgt "todo" nennen (in Jade):

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

Dann ist die hochgeladene Datei fertig, wenn Sie den Pfad und den ursprünglichen Dateinamen in 'files.todo' erhalten:

  • req.files.todo.path und
  • req.files.todo.name

andere nützliche Eigenschaften von req.files:

  • Größe (in Bytes)
  • Typ (zB 'image / png')
  • lastModifiedate
  • _writeStream.encoding (zB 'binär')
Brent Faust
quelle
Ich habe noch nie gehört, dass es so bezeichnet wird, und ich werde sagen, dass diese Leute den besten Entwickler kennen.mozilla.org/en-US/docs/JavaScript/Guide/…, also denke ich, dass wir beide falsch liegen;)
Srquinn
bodyParserist zumindest dementsprechend unsicher: andrewkelley.me/post/do-not-use-bodyparser-with-express-js.html . Jon Js Antwort hat bei mir funktioniert.
Matt Browne
Mit "unsicher" bedeutet dies lediglich, dass temporäre Dateien erstellt werden, sodass ein "Angriff" möglicherweise den Speicherplatz des Servers mit temporären Dateien füllen kann. Dies ist eher ein Robustheitsproblem, da es sich nicht um eine Sicherheitslücke handelt.
Brent Faust
19

Sie können die Middleware des Connect Body Parser in einem Konfigurationsblock in Ihrer Hauptanwendungsdatei konfigurieren:

    /** Form Handling */
    app.use(express.bodyParser({
        uploadDir: '/tmp/uploads',
        keepExtensions: true
    }))
    app.use(express.limit('5mb'));
srquinn
quelle
Dies ist tatsächlich der beste Weg, um Uploads zu handhaben, nehme ich an. Bewahren Sie die Datei auf, wenn Sie sie einfach löschen möchten, anstatt sie an einen separaten Speicherort zu kopieren. Vielen Dank.
Eastern Monk
2
@AksharPrabhuDesai Ja und nein. Nehmen wir an, Sie haben ein Tool zum Hochladen / Zuschneiden von Fotos. Wenn Sie dem Benutzer erlauben, direkt in Ihren öffentlichen Ordner hochzuladen, liegt eine schwerwiegende Sicherheitslücke vor. In diesem Fall ist es am besten, in einen tmp-Ordner hochzuladen und dann in Ihren öffentlichen Ordner zu wechseln, nachdem bestätigt wurde, dass die Datei kein Trojaner ist.
Srquinn
Scheint nicht mehr unterstützt zu werden. Sah nach einer schönen Lösung aus.
Blaze
14

Das Beste, was Sie tun können, ist, das Bild einfach auf die Festplatte hochzuladen und die URL in MongoDB zu speichern. Ruhen Sie sich aus, wenn Sie das Bild erneut abrufen. Geben Sie einfach die URL an und Sie erhalten ein Bild. Der Code zum Hochladen lautet wie folgt.

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

Speichern Sie nun den Zielpfad in Ihrer MongoDB-Datenbank.

Extrahieren Sie beim Abrufen des Bildes einfach die URL aus der MongoDB-Datenbank und verwenden Sie sie für diese Methode.

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");
    }
});
log N.
quelle
9

Versuchen Sie diesen Code. Es wird helfen.

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);
}
Dar Hamid
quelle
util.pump(ins, ous)abgeschrieben wird, könnte dies ins.pipe(ous);jetzt erledigt werden . Aber wird dadurch die Bilddatei am alten Speicherort entfernt?
Emiel Vandenbussche
8

Sie können auch Folgendes verwenden, um einen Pfad festzulegen, in dem die Datei gespeichert wird.

req.form.uploadDir = "<path>";
Manuela
quelle
2

Wenn Sie bodyParser nicht verwenden möchten, funktioniert Folgendes:

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

Wenn Sie für Express 3.0 die beeindruckenden Ereignisse verwenden möchten, müssen Sie die mehrteilige Middleware entfernen, damit Sie die neue Instanz davon erstellen können.

Um dies zu tun:

app.use(express.bodyParser());

Kann geschrieben werden als:

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

Und jetzt erstellen Sie das Formularobjekt:

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

Ich habe dies auch in meinem Blog gepostet: Beim Hochladen in Express 3.0 ein beeindruckendes Formularobjekt erhalten .

Risto Novik
quelle
Ihr Vorschlag ist irreführend, der bodyParser analysiert im Grunde das Formular. und akzeptiert beeindruckende Konfigurationsvariablen.
Marius
1
@ Timoxley Dies ist nur ein Beispiel
Risto Novik
1

Ich weiß, dass sich die ursprüngliche Frage auf bestimmte Versionen bezog, aber sie bezog sich auch auf den "neuesten" - @ JohnAllen-Beitrag ist aufgrund von Expressjs bodyParser und Verbindungsformular nicht mehr relevant

Dies zeigt den benutzerfreundlichen eingebauten bodyParser ():

 /**
 * 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');
GMeister
quelle
0

Es gibt meine Methode für mehrere Upload-Dateien:

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

Stellen Sie sicher, dass Ihr Formular enctype = "multipart / form-data" hat.

Ich hoffe das hilft dir;)

Despertaweb
quelle
0

Hier ist eine Möglichkeit, Ihre Bilder mit dem beeindruckenden Paket hochzuladen, das in späteren Express-Versionen gegenüber bodyParser empfohlen wird. Dies beinhaltet auch die Möglichkeit, die Größe Ihrer Bilder im laufenden Betrieb zu ändern:

Von meiner Website: Hochladen und Ändern der Größe von Bildern (im laufenden Betrieb) Mit Node.js und Express .

Hier ist das Wesentliche:

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

HINWEIS: Dies erfordert Image Magick für die schnelle Größenänderung des Daumens.

Tony Spiro
quelle