Nó / upload de arquivo expresso

93

Estou usando o node v0.10.26 e express v4.2.0 e sou muito novo no node. Eu tenho batido minha cabeça contra minha mesa nas últimas três horas tentando fazer um formulário de upload de arquivo funcionar com o node. Neste ponto, estou apenas tentando fazer com que req.files não retorne undefined. Minha visão é assim

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

Aqui estão minhas rotas

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;

E aqui está meu 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;

Eu vi em algum lugar que incluir methodOverride()e bodyParser({keepExtensions:true,uploadDir:path})deveria ajudar, mas não consigo nem iniciar meu servidor se adicionar essas linhas.

okawei
fonte
1
possível duplicata de upload
mscdex
Usei express 3 em vez de 4, então sua API pode ser alterada, mas acho que você precisa pesquisar no google / bing formidablee express. Você precisa habilitar o AFAIK formiableque assume o responsável por lidar com os dados do formulário multipartes, salvar os arquivos no disco local (que é o uploadDirmeio), então você pode usar algo como req.fileslê-los e processar sua lógica de negócios.
Shaun Xu
Tente remover "var bodyParser = require ('body-parser');" e em vez de usar essa var bodyParser, use algo assim: app.use (express.bodyParser ()); app.use (express.methodOverride ()); Eu não tenho tempo para testar este atm ...
Canastro
é tarde, mas pode ser útil para alguém no futuro. Aqui está um tutorial completo sobre upload de arquivo node js com mongodb programmerblog.net/nodejs-file-upload-tutorial
Jason W
Para que serve esta linha? app.use(express.static(path.join(__dirname, 'public')));
geoidésico

Respostas:

94

Problema ExpressJS:

A maior parte do middleware é removida do express 4. confira: http://www.github.com/senchalabs/connect#middleware Para middleware multipart como busboy, busboy-connect, formidable, flow, parted é necessário.

Este exemplo funciona usando middleware connect-busboy . criar / img e / pastas públicas.
Use a estrutura de pastas:

\ server.js

\ img \ "onde as coisas são enviadas para"

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

O seguinte funcionará com o formidável 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
fonte
34
Portanto, temos uma estrutura que muda APIs vitais e torna as coisas básicas terrivelmente complicadas. E esse é o módulo NodeJS mais popular?
wortwart
18
É um grande lançamento. Alterações significativas são permitidas em versões principais de acordo com as especificações do semver.org.
Stuart P. Bentley
6
Claro, semver.org permite quebrar mudanças de API em números de versão principais, mas esse é um ponto horrível de tentar justificar irritar seus usuários.
joonas.fi
1
Estou lutando há dias para fazer o upload de um arquivo funcionar com o Express. Obrigado!!!
aProperFox
1
Er, o que exatamente é "bodyParser" e de onde vem? @Mick
Robin
27

Outra opção é usar multer , que usa busboy sob o capô, mas é mais simples de configurar.

var multer = require('multer');

Use multer e defina o destino para o upload:

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

Crie um formulário em sua visualização, enctype='multipart/form-dataé necessário para que o 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")

Então, em seu POST, você pode acessar os dados sobre o arquivo:

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

Um tutorial completo sobre isso pode ser encontrado aqui .

Carasel
fonte
4
Estou me afastando do multer depois de ficar frustrado com o unknown fielderro. Tudo no meu código está correto. Ele funciona na maioria das vezes, então misteriosamente mostra essa exceção com tudo permanecendo igual (ambiente, arquivo, código, nome do arquivo)
kishu27
lance novo TypeError ('app.use () requer funções de middleware');
Kris
Você pode querer configurar assim se estiver tendo problemas em passar a função multer para 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

Aqui está uma versão simplificada ( a essência ) da resposta de Mick Cullen - em parte para provar que não precisa ser muito complexo para implementar isso; em parte, para fornecer uma referência rápida para quem não está interessado em ler páginas e páginas de código.


Você tem que fazer seu aplicativo usar connect-busboy :

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

Isso não fará nada até que você o acione. Na chamada que lida com o upload, faça o seguinte:

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

Vamos decompô-lo:

  • Você verifica se req.busboyestá definido (o middleware foi carregado corretamente)
  • Você configurou um "file"ouvinte emreq.busboy
  • Você canaliza o conteúdo de reqparareq.busboy

Dentro do listener de arquivo, há algumas coisas interessantes, mas o que realmente importa é o fileStream: este é um Readable , que pode então ser gravado em um arquivo, como você normalmente faria.

Armadilha: Você deve lidar com isso Legível, ou o Express nunca responderá à solicitação , consulte a API busboy ( seção de arquivos ).

Niels Abildgaard
fonte
19

Acho isso simples e 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
fonte
Alguém procurando uma solução mais recente com um pacote NPM atualizado deve procurar aqui. express-fileupload torna isso realmente fácil.
jaredbaszler
4

Eu precisava ser orientado com um pouco mais de detalhes do que as outras respostas fornecidas (por exemplo, como faço para gravar o arquivo em um local que decido em tempo de execução?). Espero que isso ajude outros:  

get connect-busboy:

npm install connect-busboy --save

Em seu server.js, adicione estas linhas

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

No entanto, isso parece omitir o tratamento de erros ... vou editá-lo se eu encontrar.

Edward Newell
fonte
1

Multer é um middleware node.js para lidar com multipart / form-data, que é usado principalmente para fazer upload de arquivos. É escrito no topo do busboy para máxima eficiência.

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
fonte
Multer é um middleware node.js para lidar com multipart / form-data, que é usado principalmente para fazer upload de arquivos. Ele é escrito no topo do busboy para máxima eficiência.
vipinlalrv
para melhor compreensão, editei sua resposta com sua seção de comentários, espero que você não se importe: P
Pardeep Jain
1

Aqui está uma maneira mais fácil que funcionou para mim:

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
fonte
Nossa, essa é uma implementação interessante. Funciona bem para diferentes formatos de arquivo?
Merunas Grincalaitis
0

Pessoalmente, o multer não funcionou para mim depois de semanas tentando fazer esse upload de arquivo direito. Então mudei para formidável e depois de alguns dias fiz funcionar perfeitamente sem nenhum erro, vários arquivos, express e react.js, embora o react seja opcional. Aqui está o guia: https://www.youtube.com/watch?v=jtCfvuMRsxE&t=122s

Merunas Grincalaitis
fonte
0

Se você estiver usando Node.js Express e Typescript, aqui está um exemplo de trabalho, isso também funciona com javascript, basta alterar let para var e importar para includes etc ...

primeiro importe o seguinte, certifique-se de instalar o formidable executando o seguinte comando:

npm install formidable

do que importar o seguinte:

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

então sua função como abaixo:

    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
fonte