Caricamento file Node / Express


93

Sto usando node v0.10.26 ed express v4.2.0 e sono abbastanza nuovo per node. Ho battuto la testa contro la mia scrivania nelle ultime tre ore circa cercando di ottenere un modulo di caricamento file funzionante con node. A questo punto sto solo cercando di ottenere req.files per non restituire undefined. La mia vista è così

<!DOCTYPE html>
<html>
<head>
  <title>{{ title }}</title>
  <link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
  <h1>{{ title }}</h1>
  <p>Welcome to {{ title }}</p>
  <form method='post' action='upload' enctype="multipart/form-data">
    <input type='file' name='fileUploaded'>
    <input type='submit'>
  </form>
</body>
</html>

Ecco i miei percorsi

var express = require('express');
var router = express.Router();


/* GET home page. */
router.get('/', function(req, res) {
  res.render('index', { title: 'Express' });
});

router.post('/upload', function(req, res){
console.log(req.files);
});

module.exports = router;

Ed ecco la mia app.js

var express = require('express');
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./routes/index');
var users = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hjs');

app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes);
app.use('/users', users);

/// catch 404 and forward to error handler
app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

/// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});



module.exports = app;

Ho visto da qualche parte che incluso methodOverride()e bodyParser({keepExtensions:true,uploadDir:path})avrebbe dovuto aiutare, ma non posso nemmeno avviare il mio server se aggiungo quelle linee.


1
possibile duplicato del caricamento
mscdex

Ho usato express 3 invece di 4 quindi la sua API potrebbe essere cambiata, ma penso che tu abbia bisogno di google / bing formidablee express. Per quanto ne so, è necessario abilitare formiablechi si assume la responsabilità della gestione dei dati dei moduli multipart, salvare i file nel disco locale (che è il uploadDirmezzo), quindi è possibile utilizzare qualcosa come req.filesleggerli ed elaborare la logica aziendale.
Shaun Xu

Prova a rimuovere "var bodyParser = require ('body-parser');" e invece di usare quella var bodyParser usa qualcosa del genere: app.use (express.bodyParser ()); app.use (express.methodOverride ()); Non ho tempo per provare questo atm ...
Canastro

è tardi ma potrebbe essere utile per qualcuno in futuro. Ecco un tutorial completo sul caricamento di file node js con mongodb programmerblog.net/nodejs-file-upload-tutorial
Jason W

A cosa serve questa linea? app.use(express.static(path.join(__dirname, 'public')));
geoidesica

Risposte:


94

Problema di ExpressJS:

La maggior parte del middleware viene rimossa da Express 4. controlla: http://www.github.com/senchalabs/connect#middleware Per middleware multiparte come busboy, busboy-connect, formidable, flow, parted è necessario.

Questo esempio funziona utilizzando il middleware connect-busboy . creare / img e / cartelle pubbliche.
Usa la struttura delle cartelle:

\ server.js

\ img \ "dove vengono caricate le cose"

\ public \ index.html

SERVER.JS

var express = require('express');    //Express Web Server 
var busboy = require('connect-busboy'); //middleware for form/file upload
var path = require('path');     //used for file path
var fs = require('fs-extra');       //File System - for file manipulation

var app = express();
app.use(busboy());
app.use(express.static(path.join(__dirname, 'public')));

/* ========================================================== 
Create a Route (/upload) to handle the Form submission 
(handle POST requests to /upload)
Express v4  Route definition
============================================================ */
app.route('/upload')
    .post(function (req, res, next) {

        var fstream;
        req.pipe(req.busboy);
        req.busboy.on('file', function (fieldname, file, filename) {
            console.log("Uploading: " + filename);

            //Path where image will be uploaded
            fstream = fs.createWriteStream(__dirname + '/img/' + filename);
            file.pipe(fstream);
            fstream.on('close', function () {    
                console.log("Upload Finished of " + filename);              
                res.redirect('back');           //where to go next
            });
        });
    });

var server = app.listen(3030, function() {
    console.log('Listening on port %d', server.address().port);
});

INDEX.HTML

<!DOCTYPE html>
<html lang="en" ng-app="APP">
<head>
    <meta charset="UTF-8">
    <title>angular file upload</title>
</head>

<body>
        <form method='post' action='upload' enctype="multipart/form-data">
        <input type='file' name='fileUploaded'>
        <input type='submit'>
 </body>
</html>

Quanto segue funzionerà con il formidabile SERVER.JS

var express = require('express');   //Express Web Server 
var bodyParser = require('body-parser'); //connects bodyParsing middleware
var formidable = require('formidable');
var path = require('path');     //used for file path
var fs =require('fs-extra');    //File System-needed for renaming file etc

var app = express();
app.use(express.static(path.join(__dirname, 'public')));

/* ========================================================== 
 bodyParser() required to allow Express to see the uploaded files
============================================================ */
app.use(bodyParser({defer: true}));
 app.route('/upload')
 .post(function (req, res, next) {

  var form = new formidable.IncomingForm();
    //Formidable uploads to operating systems tmp dir by default
    form.uploadDir = "./img";       //set upload directory
    form.keepExtensions = true;     //keep file extension

    form.parse(req, function(err, fields, files) {
        res.writeHead(200, {'content-type': 'text/plain'});
        res.write('received upload:\n\n');
        console.log("form.bytesReceived");
        //TESTING
        console.log("file size: "+JSON.stringify(files.fileUploaded.size));
        console.log("file path: "+JSON.stringify(files.fileUploaded.path));
        console.log("file name: "+JSON.stringify(files.fileUploaded.name));
        console.log("file type: "+JSON.stringify(files.fileUploaded.type));
        console.log("astModifiedDate: "+JSON.stringify(files.fileUploaded.lastModifiedDate));

        //Formidable changes the name of the uploaded file
        //Rename the file to its original name
        fs.rename(files.fileUploaded.path, './img/'+files.fileUploaded.name, function(err) {
        if (err)
            throw err;
          console.log('renamed complete');  
        });
          res.end();
    });
});
var server = app.listen(3030, function() {
console.log('Listening on port %d', server.address().port);
});

34
Quindi abbiamo un framework che cambia le API vitali e rende le cose di base orribilmente complicate. E questo è il modulo NodeJS più popolare?
wortwart

18
È una versione importante. Le modifiche sostanziali sono consentite nelle versioni principali secondo le specifiche di semver.org.
Stuart P. Bentley

6
Sicuramente semver.org consente di rompere le modifiche alle API nei principali numeri di versione, ma questo è un punto orribile nel cercare di giustificare il fatto di far incazzare i tuoi utenti.
joonas.fi

1
Ho lottato per giorni per ottenere un caricamento di file da utilizzare con Express. Grazie!!!
aProperFox

1
Ehm, cos'è esattamente "bodyParser" e da dove viene? @Mick
Robin

27

Un'altra opzione è usare multer , che utilizza busboy sotto il cofano, ma è più semplice da configurare.

var multer = require('multer');

Usa multer e imposta la destinazione per il caricamento:

app.use(multer({dest:'./uploads/'}));

Crea un modulo nella tua vista, enctype='multipart/form-dataè necessario per multer per funzionare:

form(role="form", action="/", method="post", enctype="multipart/form-data")
    div(class="form-group")
        label Upload File
        input(type="file", name="myfile", id="myfile")

Quindi nel tuo POST puoi accedere ai dati sul file:

app.post('/', function(req, res) {
  console.dir(req.files);
});

Un tutorial completo su questo può essere trovato qui .


4
Mi sto allontanando da multer dopo essere stato frustrato unknown fielddall'errore. Tutto nel mio codice è corretto. Funziona la maggior parte delle volte, quindi mostra misteriosamente questa eccezione con tutto ciò che rimane uguale (ambiente, file, codice, nome del file)
kishu27

lancia un nuovo TypeError ('app.use () richiede funzioni middleware');
kris

Potresti voler impostare in questo modo se hai problemi con il passaggio della funzione multer a app.use `` `var upload = multer ({dest: 'uploads /'}); var app = express () app.post ('/ profile', upload.single ('field-name'), function (req, res, next) {console.log (req.file);}) ``
Anibe Agamah

22

Ecco una versione semplificata ( il succo ) della risposta di Mick Cullen - in parte per dimostrare che non è necessario che sia molto complesso implementarla; in parte per fornire un rapido riferimento a chiunque non sia interessato a leggere pagine e pagine di codice.


Devi fare in modo che l'app utilizzi connect-busboy :

var busboy = require("connect-busboy");
app.use(busboy());

Questo non farà nulla finché non lo attivi. All'interno della chiamata che gestisce il caricamento, procedi come segue:

app.post("/upload", function(req, res) {
    if(req.busboy) {
        req.busboy.on("file", function(fieldName, fileStream, fileName, encoding, mimeType) {
            //Handle file stream here
        });
        return req.pipe(req.busboy);
    }
    //Something went wrong -- busboy was not loaded
});

Analizziamo questo:

  • Controlla se req.busboyè impostato (il middleware è stato caricato correttamente)
  • Hai impostato un "file"ascoltatorereq.busboy
  • Puoi reindirizzare il contenuto di reqareq.busboy

All'interno del file listener ci sono un paio di cose interessanti, ma ciò che conta davvero è il fileStream: questo è un Readable , che può poi essere scritto su un file, come faresti normalmente.

Insidia: è necessario gestire questo Readable, altrimenti express non risponderà mai alla richiesta , vedere l'API di busboy ( sezione file ).


19

Trovo questo, semplice ed efficiente:

const express = require('express');
const fileUpload = require('express-fileupload');
const app = express();

// default options
app.use(fileUpload());

app.post('/upload', function(req, res) {
  if (!req.files || Object.keys(req.files).length === 0) {
    return res.status(400).send('No files were uploaded.');
  }

  // The name of the input field (i.e. "sampleFile") is used to retrieve the uploaded file
  let sampleFile = req.files.sampleFile;

  // Use the mv() method to place the file somewhere on your server
  sampleFile.mv('/somewhere/on/your/server/filename.jpg', function(err) {
    if (err)
      return res.status(500).send(err);

    res.send('File uploaded!');
  });
});

express-fileupload


Qualcuno alla ricerca di una soluzione più recente con un pacchetto NPM aggiornato dovrebbe guardare qui. express-fileupload lo rende davvero facile.
jaredbaszler

4

Avevo bisogno di essere esaminato con un po 'più di dettagli rispetto alle altre risposte fornite (ad esempio, come scrivo il file in una posizione che decido in fase di esecuzione?). Si spera che questo sia di aiuto agli altri:  

ottenere connect-busboy:

npm install connect-busboy --save

Nel tuo server.js, aggiungi queste righe

let busboy = require('connect-busboy')

// ... 

app.use(busboy());

// ... 

app.post('/upload', function(req, res) {
    req.pipe(req.busboy);
    req.busboy.on('file', function(fieldname, file, filename) {
        var fstream = fs.createWriteStream('./images/' + filename); 
        file.pipe(fstream);
        fstream.on('close', function () {
            res.send('upload succeeded!');
        });
    });
});

Questo sembrerebbe omettere la gestione degli errori però ... lo modificherò se lo trovo.


1

Multer è un middleware node.js per la gestione di multipart / form-data, che viene utilizzato principalmente per il caricamento di file. È scritto sopra il busboy per la massima efficienza.

npm install --save multer


in app.js

    var multer  =   require('multer');
    var storage = multer.diskStorage({
      destination: function (req, file, callback) {
        callback(null, './public/uploads');
      },
      filename: function (req, file, callback) {
        console.log(file);
        callback(null, Date.now()+'-'+file.originalname)
      }
    });

    var upload = multer({storage: storage}).single('photo');

    router.route("/storedata").post(function(req, res, next){

        upload(req, res, function(err) {
          if(err) {
            console.log('Error Occured');
            return;
          }
          var userDetail = new mongoOp.User({
            'name':req.body.name,
            'email':req.body.email,
            'mobile':req.body.mobile,
            'address':req.body.address
          });

          console.log(req.file);

          res.end('Your File Uploaded');
          console.log('Photo Uploaded');

          userDetail.save(function(err,result){
          if (err) {
            return console.log(err)
          }
          console.log('saved to database') 
        })
      })

      res.redirect('/')

    });

Multer è un middleware node.js per la gestione di multipart / form-data, che viene utilizzato principalmente per il caricamento di file. È scritto sopra il busboy per la massima efficienza.
vipinlalrv

per una migliore comprensione ho modificato la tua risposta con la tua sezione commenti, spero che non ti dispiaccia: P
Pardeep Jain

1

Ecco un modo più semplice che ha funzionato per me:

const express = require('express');
var app = express();
var fs = require('fs');

app.post('/upload', async function(req, res) {

  var file = JSON.parse(JSON.stringify(req.files))

  var file_name = file.file.name

  //if you want just the buffer format you can use it
  var buffer = new Buffer.from(file.file.data.data)

  //uncomment await if you want to do stuff after the file is created

  /*await*/
  fs.writeFile(file_name, buffer, async(err) => {

    console.log("Successfully Written to File.");


    // do what you want with the file it is in (__dirname + "/" + file_name)

    console.log("end  :  " + new Date())

    console.log(result_stt + "")

    fs.unlink(__dirname + "/" + file_name, () => {})
    res.send(result_stt)
  });


});

oh wow, è un'implementazione interessante. Funziona bene per diversi formati di file?
Merunas Grincalaitis


0

Se stai usando Node.js Express e Typescript ecco un esempio funzionante, funziona anche con javascript, basta cambiare il let in var e l'importazione in include ecc ...

prima importa quanto segue assicurati di installare formidable eseguendo il seguente comando:

npm install formidable

che importare quanto segue:

  import * as formidable from 'formidable';
  import * as fs from 'fs';

quindi la tua funzione come sotto:

    uploadFile(req, res) {
    let form = new formidable.IncomingForm();
    form.parse(req, function (err, fields, files) {
        let oldpath = files.file.path;
        let newpath = 'C:/test/' + files.file.name;
        fs.rename(oldpath, newpath, function (err) {
            if (err) throw err;
            res.write('File uploaded and moved!');
            res.end();
        });
    });
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.