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.


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

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 .


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


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


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.


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

    });

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


});

Nossa, essa é uma implementação interessante. Funciona bem para diferentes formatos de arquivo?
Merunas Grincalaitis


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();
        });
    });
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.