Carga de archivos de nodo / expreso

93

Estoy usando el nodo v0.10.26 y express v4.2.0 y soy bastante nuevo en el nodo. He estado golpeando mi cabeza contra mi escritorio durante las últimas tres horas tratando de que un formulario de carga de archivos funcione con node. En este punto, solo estoy tratando de obtener archivos req para que no devuelvan undefined. Mi vista se ve así

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

Aquí están mis rutas

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;

Y aquí está mi 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;

Vi en algún lugar que se incluía methodOverride()y bodyParser({keepExtensions:true,uploadDir:path})se suponía que debía ayudar, pero ni siquiera puedo iniciar mi servidor si agrego esas líneas.

okawei
fuente
1
posible duplicado de carga
mscdex
Usé express 3 en lugar de 4, por lo que su api podría cambiarse, pero creo que necesitas google / bing formidabley express. AFAIK, debe habilitar lo formiableque se encarga de tratar con datos de formularios de varias partes, guardar los archivos en el disco local (que es el uploadDirmedio) y luego puede usar algo como req.filesleerlos y procesar su lógica comercial.
Shaun Xu
Intente eliminar "var bodyParser = require ('body-parser');" y en lugar de usar esa var bodyParser, use algo como esto: app.use (express.bodyParser ()); app.use (express.methodOverride ()); No tengo tiempo para probar este
cajero automático
es tarde, pero puede ser útil para alguien en el futuro. Aquí hay un tutorial completo sobre la carga de archivos js de nodo con mongodb programmerblog.net/nodejs-file-upload-tutorial
Jason W
¿Para qué es esta línea? app.use(express.static(path.join(__dirname, 'public')));
geodésico

Respuestas:

94

Problema de ExpressJS:

La mayor parte del middleware se elimina de express 4. echa un vistazo a: http://www.github.com/senchalabs/connect#middleware Para middleware multiparte como busboy, busboy-connect, formidable, flow, parted es necesario.

Este ejemplo funciona con el middleware connect-busboy . crear carpetas / img y / public.
Utilice la estructura de carpetas:

\ server.js

\ img \ "donde se cargan las cosas"

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

ÍNDICE.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>

Lo siguiente funcionará con el 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
fuente
34
Así que tenemos un marco que cambia las API vitales y hace que las cosas básicas sean terriblemente complicadas. ¿Y ese es el módulo NodeJS más popular?
wortwart
18
Es un lanzamiento importante. Se permiten cambios importantes en las versiones principales según la especificación de semver.org.
Stuart P. Bentley
6
Claro que semver.org permite romper los cambios de API en los números de versión principales, pero ese es un punto horrible para tratar de justificar el enojo de los usuarios.
joonas.fi
1
He estado luchando durante días para que la carga de un archivo funcione con Express. ¡¡¡Gracias!!!
aProperFox
1
Er, ¿qué es exactamente "bodyParser" y de dónde viene? @Mick
Robin
27

Otra opción es usar multer , que usa ayudante de camarero debajo del capó, pero es más simple de configurar.

var multer = require('multer');

Utilice multer y establezca el destino para la carga:

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

Cree un formulario en su vista, enctype='multipart/form-dataes necesario para que multer funcione:

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

Luego en tu POST puedes acceder a los datos sobre el archivo:

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

Puede encontrar un tutorial completo sobre esto aquí .

Carasel
fuente
4
Me estoy alejando de multer después de frustrarme con el unknown fielderror. Todo en mi código es correcto. Funciona la mayor parte del tiempo y luego muestra misteriosamente esta excepción con todo lo que permanece igual (entorno, archivo, código, nombre de archivo)
kishu27
lanzar nuevo TypeError ('app.use () requiere funciones de middleware');
kris
Es posible que desee configurarlo así si tiene problemas para pasar la función 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

Aquí hay una versión simplificada ( la esencia ) de la respuesta de Mick Cullen, en parte para demostrar que no tiene por qué ser muy complejo implementar esto; en parte para brindar una referencia rápida para cualquiera que no esté interesado en leer páginas y páginas de código.


Tienes que hacer que tu aplicación use connect-busboy :

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

Esto no hará nada hasta que lo active. Dentro de la llamada que maneja la carga, haga lo siguiente:

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

Analicemos esto:

  • Verifica si req.busboyestá configurado (el middleware se cargó correctamente)
  • Configuras un "file"oyente enreq.busboy
  • Canalizas el contenido de reqareq.busboy

Dentro del detector de archivos hay un par de cosas interesantes, pero lo que realmente importa es fileStream: este es un archivo legible , que luego se puede escribir en un archivo, como lo haría normalmente.

Escollo: debe manejar este legible, o express nunca responderá a la solicitud , consulte la API de ayudante de camarero ( sección de archivos ).

Niels Abildgaard
fuente
19

Encuentro esto, simple y eficiente:

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
fuente
Alguien que busque una solución más reciente con un paquete NPM actualizado debería buscar aquí. express-fileupload hace que esto sea realmente fácil.
jaredbaszler
4

Necesitaba que me guiaran con un poco más de detalle que las otras respuestas proporcionadas (por ejemplo, ¿cómo escribo el archivo en una ubicación que decida en tiempo de ejecución?). Con suerte, esto será de ayuda para otros:  

conseguir connect-busboy:

npm install connect-busboy --save

En su server.js, agregue estas líneas

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

Sin embargo, esto parecería omitir el manejo de errores ... lo editaré si lo encuentro.

Edward Newell
fuente
1

Multer es un middleware de node.js para manejar datos de formularios / multiparte, que se utiliza principalmente para cargar archivos. Está escrito encima del ayudante de camarero para una máxima eficiencia.

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
fuente
Multer es un middleware de node.js para manejar datos de formularios / multiparte, que se utiliza principalmente para cargar archivos. Está escrito encima del ayudante de camarero para una máxima eficiencia.
vipinlalrv
para una mejor comprensión, he editado su respuesta con la sección de comentarios, espero que no le
importe
1

Aquí hay una forma más fácil que funcionó para mí:

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
fuente
oh wow, esa es una implementación interesante. ¿Funciona bien para diferentes formatos de archivo?
Merunas Grincalaitis
0

Personalmente, multer no funcionó para mí después de semanas tratando de hacer bien esta carga de archivos. Luego cambio a formidable y después de unos días lo conseguí funcionando perfectamente sin ningún error, múltiples archivos, express y react.js aunque react es opcional. Aquí está la guía: https://www.youtube.com/watch?v=jtCfvuMRsxE&t=122s

Merunas Grincalaitis
fuente
0

Si está utilizando Node.js Express y Typecript, aquí hay un ejemplo de trabajo, esto también funciona con javascript, simplemente cambie el let a var y el import to includes, etc.

Primero importe lo siguiente, asegúrese de instalar formidable ejecutando el siguiente comando:

npm install formidable

que importar lo siguiente:

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

entonces tu función como abajo:

    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
fuente