Téléchargement de fichiers Node / Express

93

J'utilise node v0.10.26 et express v4.2.0 et je suis assez nouveau dans node. Je me cogne la tête contre mon bureau depuis environ trois heures pour essayer de faire fonctionner un formulaire de téléchargement de fichiers avec node. À ce stade, j'essaie simplement de faire en sorte que req.files ne retourne pas undefined. Ma vue ressemble à ceci

<!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>

Voici mes itinéraires

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;

Et voici mon 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;

J'ai vu quelque part cela incluant methodOverride()et bodyParser({keepExtensions:true,uploadDir:path})était censé aider mais je ne peux même pas lancer mon serveur si j'ajoute ces lignes.

okawei
la source
1
duplication possible du téléchargement
mscdex
J'ai utilisé express 3 au lieu de 4, donc son API peut être modifiée, mais je pense que vous devez google / bing formidableet express. AFAIK vous devez activer formiablece qui prend la responsabilité de traiter les données de formulaire en plusieurs parties , enregistrez les fichiers sur le disque local (ce qui est le uploadDirmoyen), puis vous pouvez utiliser quelque chose comme req.filespour les lire et traiter votre logique métier.
Shaun Xu
Essayez de supprimer "var bodyParser = require ('body-parser');" et au lieu d'utiliser ce bodyParser var, utilisez quelque chose comme ceci: app.use (express.bodyParser ()); app.use (express.methodOverride ()); Je n'ai pas le temps de tester cet atm ...
Canastro
c'est tard mais peut être utile pour quelqu'un à l'avenir. Voici un tutoriel complet sur le téléchargement de fichiers node js avec mongodb programmerblog.net/nodejs-file-upload-tutorial
Jason W
A quoi sert cette ligne? app.use(express.static(path.join(__dirname, 'public')));
géoidesique

Réponses:

94

Problème ExpressJS:

La plupart des middlewares sont supprimés d'Express 4. Vérifiez: http://www.github.com/senchalabs/connect#middleware Pour les middlewares en plusieurs parties comme busboy, busboy-connect, formidable, flow, parted est nécessaire.

Cet exemple fonctionne avec le middleware connect-busboy . créer des dossiers / img et / public.
Utilisez la structure des dossiers:

\ server.js

\ img \ "où les éléments sont téléchargés vers"

\ 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>

Ce qui suit fonctionnera avec le formidable 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);
});
Mick Cullen
la source
34
Nous avons donc un cadre qui change les API vitales et complique horriblement les choses de base. Et c'est le module NodeJS le plus populaire?
wortwart
18
C'est une version majeure. Les changements de rupture sont autorisés dans les versions majeures selon la spécification semver.org.
Stuart P. Bentley
6
Bien sûr, semver.org permet de briser les changements d'API dans les numéros de version majeurs, mais c'est un point horrible pour essayer de justifier la colère de vos utilisateurs.
joonas.fi
1
Cela fait des jours que je lutte pour obtenir un téléchargement de fichier pour fonctionner avec express. Je vous remercie!!!
aProperFox
1
Euh, qu'est-ce que "bodyParser" et d'où vient-il? @Mick
Robin
27

Une autre option consiste à utiliser multer , qui utilise busboy sous le capot, mais qui est plus simple à installer.

var multer = require('multer');

Utilisez multer et définissez la destination du téléchargement:

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

Créer un formulaire dans votre vue, enctype='multipart/form-dataest nécessaire pour que multer fonctionne:

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

Ensuite, dans votre POST, vous pouvez accéder aux données sur le fichier:

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

Un tutoriel complet à ce sujet peut être trouvé ici .

Carasel
la source
4
Je m'éloigne de multer après être frustré par l' unknown fielderreur. Tout dans mon code est correct. Cela fonctionne la plupart du temps puis montre mystérieusement cette exception avec tout restant identique (environnement, fichier, code, nom de fichier)
kishu27
throw new TypeError ('app.use () nécessite des fonctions middleware');
kris
Vous voudrez peut-être configurer comme ceci si vous rencontrez des problèmes pour passer la fonction multer à 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

Voici une version simplifiée ( l'essentiel ) de la réponse de Mick Cullen - en partie pour prouver que cela n'a pas besoin d'être très complexe pour implémenter cela; en partie pour donner une référence rapide à quiconque n'est pas intéressé par la lecture de pages et de pages de code.


Vous devez faire en sorte que votre application utilise connect-busboy :

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

Cela ne fera rien tant que vous ne le déclencherez pas. Dans l'appel qui gère le téléchargement, procédez comme suit:

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

Décomposons ceci:

  • Vous vérifiez si req.busboyest défini (le middleware a été chargé correctement)
  • Vous avez configuré un "file"auditeur surreq.busboy
  • Vous redirigez le contenu de reqlareq.busboy

À l'intérieur de l'écouteur de fichiers, il y a quelques choses intéressantes, mais ce qui compte vraiment, c'est fileStream: c'est un fichier lisible , qui peut ensuite être écrit dans un fichier, comme vous le feriez habituellement.

Piège: Vous devez gérer ce Readable, sinon express ne répondra jamais à la demande , voir l'API busboy ( section fichier ).

Niels Abildgaard
la source
19

Je trouve cela simple et efficace:

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

Yago ML
la source
Quelqu'un à la recherche d'une solution plus récente avec un package NPM à jour devrait regarder ici. express-fileupload rend cela vraiment facile.
jaredbaszler
4

J'avais besoin d'être exploré avec un peu plus de détails que les autres réponses fournies (par exemple, comment écrire le fichier à un emplacement que je décide lors de l'exécution?). J'espère que cela aidera les autres:  

obtenir connect-busboy:

npm install connect-busboy --save

Dans votre server.js, ajoutez ces lignes

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

Cela semblerait cependant omettre la gestion des erreurs ... le modifiera si je le trouve.

Edward Newell
la source
1

Multer est un middleware node.js pour la gestion de multipart / form-data, qui est principalement utilisé pour télécharger des fichiers. Il est écrit sur le busboy pour une efficacité maximale.

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('/')

    });
vipinlalrv
la source
Multer est un middleware node.js pour la gestion de multipart / form-data, qui est principalement utilisé pour télécharger des fichiers. Il est écrit sur le busboy pour une efficacité maximale.
vipinlalrv
pour une meilleure compréhension, j'ai modifié votre réponse avec votre section de commentaires, j'espère que cela ne vous dérange pas: P
Pardeep Jain
1

Voici un moyen plus simple qui a fonctionné pour moi:

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


});
hamzan
la source
oh wow c'est une implémentation intéressante. Cela fonctionne-t-il bien pour différents formats de fichiers?
Merunas Grincalaitis
0

Personnellement, multer n'a pas fonctionné pour moi après des semaines à essayer de faire correctement ce téléchargement de fichiers. Ensuite, je passe à formidable et après quelques jours je l'ai fait fonctionner parfaitement sans aucune erreur, plusieurs fichiers, express et react.js même si react est facultatif. Voici le guide: https://www.youtube.com/watch?v=jtCfvuMRsxE&t=122s

Merunas Grincalaitis
la source
0

Si vous utilisez Node.js Express et Typescript, voici un exemple de travail, cela fonctionne également avec javascript, changez simplement le let en var et l'importation en includes etc ...

importez d'abord les éléments suivants, assurez-vous d'installer formidable en exécutant la commande suivante:

npm install formidable

que d'importer ce qui suit:

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

alors votre fonction comme ci-dessous:

    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();
        });
    });
}
MJ X
la source