Tải lên tệp Node / Express


93

Tôi đang sử dụng nút v0.10.26 và express v4.2.0 và tôi khá mới với nút. Tôi đã đập đầu vào bàn của mình trong hơn ba giờ qua để cố gắng tải một biểu mẫu tải lên tệp hoạt động với nút. Tại thời điểm này, tôi chỉ đang cố gắng lấy req.files để không trả về undefined. Chế độ xem của tôi trông như thế này

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

Đây là các tuyến đường của tôi

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;

Và đây là app.js của tôi

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;

Tôi đã thấy ở đâu đó bao gồm methodOverride()bodyParser({keepExtensions:true,uploadDir:path})được cho là sẽ giúp đỡ nhưng tôi thậm chí không thể khởi chạy máy chủ của mình nếu tôi thêm những dòng đó.



Tôi đã sử dụng express 3 thay vì 4 nên api của nó có thể bị thay đổi, nhưng tôi nghĩ bạn cần phải google / bing formidableexpress. AFAIK bạn cần bật tính formiablenăng này chịu trách nhiệm xử lý dữ liệu biểu mẫu nhiều phần, lưu các tệp trong đĩa cục bộ (là uploadDirphương tiện) sau đó bạn có thể sử dụng một cái gì đó như req.filesđể đọc chúng và xử lý logic nghiệp vụ của mình.
Shaun Xu

Cố gắng loại bỏ "var bodyParser = demand ('body-parser');" và thay vì sử dụng var bodyParser đó, hãy sử dụng một cái gì đó như sau: app.use (express.bodyParser ()); app.use (express.methodOverride ()); Tôi không có thời gian để kiểm tra atm này ...
Canastro

tuy muộn nhưng có thể hữu ích cho một số người trong tương lai. Đây là một hướng dẫn đầy đủ về nút js tải lên tập tin với MongoDB programmerblog.net/nodejs-file-upload-tutorial
Jason W

Dòng này để làm gì? app.use(express.static(path.join(__dirname, 'public')));
geoidesic

Câu trả lời:


94

Sự cố ExpressJS:

Hầu hết phần mềm trung gian bị xóa khỏi express 4. Kiểm tra: http://www.github.com/senchalabs/connect#middleware Đối với phần mềm trung gian nhiều phần như busboy, busboy-connect, ghê gớm, flow, parted là cần thiết.

Ví dụ này hoạt động bằng cách sử dụng phần mềm trung gian connect-busboy . tạo / img và / thư mục chung.
Sử dụng cấu trúc thư mục:

\ server.js

\ img \ "nơi nội dung được tải lên"

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

Phần sau sẽ hoạt động với SERVER.JS đáng gờm

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
Vì vậy, chúng tôi có một khuôn khổ thay đổi các API quan trọng và làm cho những thứ cơ bản trở nên phức tạp kinh khủng. Và đó là mô-đun NodeJS phổ biến nhất?
wortwart,

18
Đó là một bản phát hành lớn. Các thay đổi đột phá được phép trong các bản phát hành chính theo thông số của semver.org.
Stuart P. Bentley

6
Chắc chắn semver.org cho phép phá vỡ các thay đổi API trong các số phiên bản chính, nhưng đó là một điểm kinh khủng khi cố gắng bào chữa cho người dùng của bạn.
joonas.fi

1
Tôi đã vật lộn trong nhiều ngày để tải tệp lên hoạt động với express. Cảm ơn bạn!!!
aProperFox

1
Ơ, chính xác thì "bodyParser" là gì và nó đến từ đâu? @Mick
Robin

27

Một lựa chọn khác là sử dụng multer , sử dụng busboy dưới mui xe, nhưng thiết lập đơn giản hơn.

var multer = require('multer');

Sử dụng multer và đặt đích cho tải lên:

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

Tạo một biểu mẫu trong chế độ xem của bạn, enctype='multipart/form-datalà bắt buộc để multer hoạt động:

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

Sau đó, trong BÀI ĐĂNG của bạn, bạn có thể truy cập dữ liệu về tệp:

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

Hướng dẫn đầy đủ về điều này có thể được tìm thấy ở đây .


4
Tôi đang chuyển bỏ đa dạng biểu mẫu sau khi thất vọng với unknown fieldlỗi. Mọi thứ trong mã của tôi đều đúng. Nó hoạt động hầu hết thời gian sau đó cho thấy ngoại lệ này một cách bí ẩn với mọi thứ vẫn như cũ (môi trường, tệp, mã, tên tệp)
kishu27

ném TypeError mới ('app.use () yêu cầu các chức năng phần mềm trung gian');
kris

Bạn có thể muốn thiết lập như vậy nếu bạn đang gặp sự cố với việc chuyển hàm multer tới 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

Đây là phiên bản đơn giản hóa ( ý chính ) của câu trả lời của Mick Cullen - một phần để chứng minh rằng nó không cần quá phức tạp để thực hiện điều này; một phần để cung cấp tài liệu tham khảo nhanh cho bất kỳ ai không quan tâm đến việc đọc các trang và các trang mã.


Bạn phải làm cho ứng dụng của bạn sử dụng connect-busboy :

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

Điều này sẽ không làm bất cứ điều gì cho đến khi bạn kích hoạt nó. Trong lệnh gọi xử lý tải lên, hãy làm như sau:

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

Hãy chia nhỏ điều này:

  • Bạn kiểm tra xem đã req.busboyđược đặt chưa (phần mềm trung gian đã được tải đúng cách)
  • Bạn thiết lập một "file"người nghe trênreq.busboy
  • Bạn chuyển nội dung của reqtớireq.busboy

Bên trong trình xử lý tệp có một vài điều thú vị, nhưng điều thực sự quan trọng là fileStream: đây là tệp Có thể đọc , sau đó có thể được ghi vào tệp, giống như bạn thường làm.

Cạm bẫy: Bạn phải xử lý điều này Có thể đọc được, hoặc express sẽ không bao giờ phản hồi yêu cầu , hãy xem API busboy ( phần tệp ).


19

Tôi thấy điều này, đơn giản và hiệu quả:

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


Ai đó đang tìm kiếm giải pháp mới hơn với gói NPM cập nhật nên xem tại đây. express-fileupload làm cho việc này thực sự dễ dàng.
jaredbaszler

4

Tôi cần được hướng dẫn chi tiết hơn một chút so với các câu trả lời khác được cung cấp (ví dụ: làm cách nào để ghi tệp vào vị trí mà tôi quyết định trong thời gian chạy?). Hy vọng rằng điều này sẽ giúp ích cho những người khác:  

nhận kết nối-busboy:

npm install connect-busboy --save

Trong server.js của bạn, hãy thêm những dòng này

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

Tuy nhiên, điều này dường như sẽ bỏ qua việc xử lý lỗi ... sẽ chỉnh sửa nó nếu tôi tìm thấy nó.


1

Multer là một phần mềm trung gian của node.js để xử lý dữ liệu đa phần / biểu mẫu, chủ yếu được sử dụng để tải tệp lên. Nó được viết trên đầu trang của busboy để đạt hiệu quả tối đa.

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 là một phần mềm trung gian của node.js để xử lý dữ liệu đa phần / biểu mẫu, chủ yếu được sử dụng để tải tệp lên. Nó được viết trên đầu trang của busboy để đạt hiệu quả tối đa.
vipinlalrv

để hiểu tốt hơn tôi đã chỉnh sửa câu trả lời của bạn với phần bình luận của bạn, tôi hy vọng bạn không nhớ: P
Pardeep Jain

1

Đây là một cách dễ dàng hơn phù hợp với tôi:

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


});

ồ ồ, đó là một triển khai thú vị. Nó có hoạt động tốt cho các định dạng tệp khác nhau không?
Merunas Grincalaitis

0

Cá nhân tôi đã không làm việc với multer sau nhiều tuần cố gắng tải lên tệp này đúng. Sau đó, tôi chuyển sang dạng ghê gớm và sau một vài ngày, tôi thấy nó hoạt động hoàn hảo mà không có bất kỳ lỗi nào, nhiều tệp, express và react.js mặc dù react là tùy chọn. Đây là hướng dẫn: https://www.youtube.com/watch?v=jtCfvuMRsxE&t=122s


0

Nếu bạn đang sử dụng Node.js Express và Typescript thì đây là một ví dụ hoạt động, điều này cũng hoạt động với javascript, chỉ cần thay đổi let thành var và nhập thành bao gồm, v.v.

trước tiên hãy nhập phần sau, hãy đảm bảo rằng bạn cài đặt thành công bằng cách chạy lệnh sau:

npm install formidable

hơn nhập khẩu sau:

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

thì chức năng của bạn như dưới đây:

    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();
        });
    });
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.