Mengupload gambar menggunakan Node.js, Express, dan Mongoose

102

Harap pertimbangkan jawaban lebih baru yang memiliki lebih banyak informasi terkini karena banyak hal telah berubah selama bertahun-tahun!

Karena banyak pustaka Node.js baru dengan cepat menjadi usang dan hanya ada sedikit contoh yang ingin saya tanyakan tentang mengunggah gambar menggunakan:

  • Node.js (v0.4.1)
  • Ekspres (1.0.7)
  • Mongoose (1.1.0).

Bagaimana orang lain melakukannya?

Saya telah menemukan: node-formidable , tetapi saya baru dalam mengunggah gambar secara umum jadi saya ingin mempelajari hal-hal umum dan cara melakukannya menggunakan Node.js dan Express.

JohnAllen
sumber
12
Perbarui Versi Express yang lebih baru memiliki fungsi ini di
dalamnya
4
2015 tl; dr- kirim permintaan multibagian / formulir ke server Anda dan parsing dengan Multer karena BodyParser tidak lagi mem-parsing file. npm install multer --savedan kemudian di aplikasi Anda, Anda dapat mengakses req.files.your_file_param_namedan menyimpan ke s3 dengan aws-sdkataufs.writeFile(...)
pengguna

Jawaban:

74

Saya akan menjawab pertanyaan saya sendiri untuk pertama kalinya. Saya menemukan contoh langsung dari sumbernya. Mohon maafkan indentasi yang buruk. Saya tidak yakin bagaimana cara membuat indentasi dengan benar saat menyalin dan menempel. Kode tersebut berasal langsung dari multipart/form-datacontoh Express di 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
sumber
3
Ya tapi bagaimana Anda menyimpan file?
Nick Retallack
1
@NickRetallack file yang disimpan disimpan di files.image.path
Robin Duckett
@ robin-duckett, bagaimana Anda menentukan nama file dan jalur sebelumnya?
Luc
4
@ Luc: Anda tidak, itu disimpan ke direktori temp di mana Anda memindahkannya ke tempat lain.
kevmo314
1
Ini adalah cara Anda mengkonfigurasi direktori upload secara express: // CATATAN: gunakan jalur absolut ke direktori upload untuk menghindari masalah pada submodul! // app.use (express.bodyParser ({uploadDir: uploadDir}));
Risadinha
47

Karena Anda menggunakan express, cukup tambahkan bodyParser:

app.use(express.bodyParser());

maka rute Anda secara otomatis memiliki akses ke file yang diunggah di file req.file:

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

Jika Anda memberi nama kontrol input "rencana" seperti ini (di Jade):

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

Kemudian file yang diunggah sudah siap pada saat Anda mendapatkan jalur dan nama file asli di 'files.todo':

  • req.files.todo.path, dan
  • req.files.todo.name

properti req.files berguna lainnya:

  • ukuran (dalam byte)
  • jenis (misalnya, 'image / png')
  • lastModifiedate
  • _writeStream.encoding (misalnya, 'binary')
Brent Faust
sumber
Saya belum pernah mendengarnya disebut seperti itu dan saya akan melanjutkan dan mengatakan bahwa orang-orang ini tahu developer terbaik.mozilla.org/en-US/docs/JavaScript/Guide/… jadi saya rasa kami berdua salah;)
srquinn
bodyParsertidak aman, setidaknya menurut ini: andrewkelley.me/post/do-not-use-bodyparser-with-express-js.html . Jawaban Jon J berhasil untuk saya.
Matt Browne
Dengan "tidak aman", ini hanya berarti bahwa file temporer dibuat, sehingga "serangan" mungkin dapat mengisi ruang disk server dengan file temp. Ini lebih merupakan masalah ketahanan, karena ini bukan lubang keamanan.
Brent Faust
19

Anda dapat mengonfigurasi middleware connect body parser di blok konfigurasi di file aplikasi utama Anda:

    /** Form Handling */
    app.use(express.bodyParser({
        uploadDir: '/tmp/uploads',
        keepExtensions: true
    }))
    app.use(express.limit('5mb'));
srquinn.dll
sumber
Ini sebenarnya cara terbaik untuk menangani unggahan, saya kira. Simpan file jika Anda ingin menghapusnya saja daripada menyalinnya ke lokasi terpisah. Terima kasih.
Biksu Timur
2
@AksharPrabhuDesai Ya dan tidak. Katakanlah Anda memiliki alat unggah / potong foto. Jika Anda mengizinkan pengguna untuk mengunggah langsung ke folder publik Anda, Anda mengalami cacat keamanan yang serius. Dalam kasus ini, yang terbaik adalah mengunggah ke folder tmp dan kemudian pindah ke folder publik Anda setelah memastikan bahwa file tersebut bukan Trojan.
srquinn
Sepertinya tidak didukung lagi. Sepertinya solusi yang bagus.
Blaze
14

Lihat, hal terbaik yang dapat Anda lakukan adalah mengunggah gambar ke disk dan menyimpan URL di MongoDB. Beristirahatlah saat Anda mengambil kembali gambar itu. Cukup tentukan URL, dan Anda akan mendapatkan gambar. Kode untuk mengupload adalah sebagai berikut.

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

Sekarang simpan jalur target di database MongoDB Anda.

Sekali lagi, saat mengambil gambar, cukup ekstrak URL dari database MongoDB, dan gunakan pada metode ini.

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
sumber
9

Coba kode ini. Ini akan membantu.

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
sumber
util.pump(ins, ous)disusutkan, ini bisa dilakukan ins.pipe(ous);sekarang. Tetapi apakah ini akan menghapus file gambar di lokasi lama?
Emiel Vandenbussche
8

Anda juga dapat menggunakan yang berikut ini untuk menyetel jalur penyimpanan file.

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

Sekali lagi jika Anda tidak ingin menggunakan bodyParser, berikut ini berfungsi:

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
sumber
2

Untuk Express 3.0, jika Anda ingin menggunakan peristiwa hebat, Anda harus menghapus middleware multi bagian, sehingga Anda dapat membuat instance baru darinya.

Untuk melakukan ini:

app.use(express.bodyParser());

Dapat ditulis sebagai:

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

Dan sekarang buat objek formulir:

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

Saya juga telah memposting ini di blog saya, Mendapatkan objek formulir yang tangguh di Express 3.0 saat diunggah .

Risto Novik
sumber
Saran Anda salah arah, bodyParser pada dasarnya mengurai formulir. dan menerima variabel config yang tangguh.
Marius
1
@timoxley ini hanya contoh
Risto Novik
1

Saya tahu bahwa pertanyaan asli terkait dengan versi tertentu, tetapi juga merujuk ke "terbaru" - kiriman @JohnAllen tidak lagi relevan karena Expressjs bodyParser dan connect-form

Ini mendemonstrasikan bodyParser () built-in yang mudah digunakan:

 /**
 * 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
sumber
0

Ada metode saya untuk mengupload banyak file:

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

Pastikan formulir Anda memiliki enctype = "multipart / form-data"

Saya harap ini membantu Anda;)

Despertaweb
sumber
0

Berikut adalah cara untuk mengupload gambar Anda menggunakan paket yang hebat, yang direkomendasikan melalui bodyParser di versi Express yang lebih baru. Ini juga termasuk kemampuan untuk mengubah ukuran gambar Anda dengan cepat:

Dari situs web saya: Mengunggah dan Mengubah Ukuran Gambar (dengan cepat) Dengan Node.js dan Express .

Inilah intinya:

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

CATATAN: Ini membutuhkan Image Magick untuk mengubah ukuran ibu jari dengan cepat.

Tony Spiro
sumber