node.js Node/Express 文件上传
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23691194/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Node/Express file upload
提问by okawei
I'm using node v0.10.26 and express v4.2.0 and I'm pretty new to node. I've been beating my head against my desk for the past three or so hours trying to get a file upload form working with node. At this point I'm just trying to get req.files to not return undefined. My view looks like this
我正在使用 node v0.10.26 和 express v4.2.0,我对 node 还很陌生。在过去的三个小时左右的时间里,我一直在用头撞我的桌子,试图让文件上传表单与 node.js 一起工作。在这一点上,我只是想让 req.files 不返回 undefined。我的观点是这样的
<!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>
Here are my routes
这是我的路线
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;
And here's my app.js
这是我的 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;
I saw somewhere that including methodOverride()and bodyParser({keepExtensions:true,uploadDir:path})was supposed to help but I can't even launch my server if I add those lines.
我看到某处包括methodOverride()并且bodyParser({keepExtensions:true,uploadDir:path})应该提供帮助,但如果我添加这些行,我什至无法启动我的服务器。
回答by Mick Cullen
ExpressJS Issue:
ExpressJS 问题:
Most of the middleware is removed from express 4. check out: http://www.github.com/senchalabs/connect#middlewareFor multipart middleware like busboy, busboy-connect, formidable, flow, parted is needed.
大多数中间件从 express 4 中删除。请查看:http: //www.github.com/senchalabs/connect#middleware对于像 busboy、busboy-connect、formidable、flow、parted 这样的多部分中间件是需要的。
This example works using connect-busboymiddleware.
create /img and /public folders.
Use the folder structure:
此示例使用connect-busboy中间件工作。创建 /img 和 /public 文件夹。
使用文件夹结构:
\server.js
\server.js
\img\"where stuff is uploaded to"
\img\“上传东西的地方”
\public\index.html
\public\index.html
SERVER.JS
服务端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>
The following will work with formidable SERVER.JS
以下将与强大的 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);
});
回答by Carasel
Another option is to use multer, which uses busboy under the hood, but is simpler to set up.
另一种选择是使用multer,它在幕后使用busboy,但设置起来更简单。
var multer = require('multer');
Use multer and set the destination for the upload:
使用 multer 并设置上传目标:
app.use(multer({dest:'./uploads/'}));
Create a form in your view, enctype='multipart/form-datais required for multer to work:
在您的视图中创建一个表单,这enctype='multipart/form-data是multer 工作所必需的:
form(role="form", action="/", method="post", enctype="multipart/form-data")
div(class="form-group")
label Upload File
input(type="file", name="myfile", id="myfile")
Then in your POST you can access the data about the file:
然后在您的 POST 中,您可以访问有关该文件的数据:
app.post('/', function(req, res) {
console.dir(req.files);
});
A full tutorial on this can be found here.
可以在此处找到有关此的完整教程。
回答by Niels Abildgaard
Here is a simplified version (the gist) of Mick Cullen's answer-- in part to prove that it needn't be very complex to implement this; in part to give a quick reference for anyone who isn't interested in reading pages and pages of code.
这是Mick Cullen答案的简化版本(要点)——部分是为了证明实现这一点不需要非常复杂;部分是为对阅读页面和代码页面不感兴趣的任何人提供快速参考。
You have to make you app use connect-busboy:
你必须让你的应用程序使用connect-busboy:
var busboy = require("connect-busboy");
app.use(busboy());
This will not do anything until you trigger it. Within the call that handles uploading, do the following:
在您触发它之前,这不会做任何事情。在处理上传的调用中,执行以下操作:
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
});
Let's break this down:
让我们分解一下:
- You check if
req.busboyis set (the middleware was loaded correctly) - You set up a
"file"listener onreq.busboy - You pipe the contents of
reqtoreq.busboy
- 您检查是否
req.busboy已设置(中间件已正确加载) - 你设置了一个
"file"监听器req.busboy - 您将内容通过管道
req传输到req.busboy
Inside the file listener there are a couple of interesting things, but what really matters is the fileStream: this is a Readable, that can then be written to a file, like you usually would.
在文件侦听器内部有一些有趣的事情,但真正重要的是fileStream:这是一个Readable,然后可以像通常那样将其写入文件。
Pitfall: You must handle this Readable, or express will never respond to the request, see the busboy API(filesection).
陷阱:您必须处理这个 Readable,否则 express 将永远不会响应请求,请参阅busboy API(文件部分)。
回答by Yago ML
I find this, simple and efficient:
我发现这简单而有效:
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!');
});
});
回答by Edward Newell
I needed to be walked through with a bit more detail than the other answers provided (e.g. how do I write the file to a location I decide at runtime?). Hopefully this is of help to others:
我需要比提供的其他答案更详细一点(例如,如何将文件写入我在运行时决定的位置?)。希望这对其他人有帮助:
get connect-busboy:
获取连接busboy:
npm install connect-busboy --save
In your server.js, add these lines
在你的 server.js 中,添加这些行
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!');
});
});
});
This would seem to omit error handling though... will edit it in if I find it.
虽然这似乎省略了错误处理...如果我找到它会编辑它。
回答by hamzan
Here is an easier way that worked for me:
这是一种对我有用的更简单的方法:
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)
});
});
回答by Merunas Grincalaitis
Personally multer didn't work for me after weeks trying to get this file upload thing right. Then I switch to formidable and after a few days I got it working perfectly without any error, multiple files, express and react.js even though react is optional. Here's the guide: https://www.youtube.com/watch?v=jtCfvuMRsxE&t=122s
经过数周的尝试使此文件上传正确后,我个人 multer 对我不起作用。然后我切换到强大的,几天后我让它完美地工作,没有任何错误,多个文件,express 和 react.js,即使 react 是可选的。这是指南:https: //www.youtube.com/watch?v=jtCfvuMRsxE&t=122s
回答by MJVM
If you are using Node.js Express and Typescript here is a working example, this works with javascript also, just change the let to var and the import to includes etc...
如果您使用的是 Node.js Express 和 Typescript,这里是一个工作示例,这也适用于 javascript,只需将 let 更改为 var 并将导入更改为包含等...
first import the following make sure you install formidable by running the following command:
首先导入以下内容,确保通过运行以下命令安装 formidable:
npm install formidable
than import the following:
比导入以下内容:
import * as formidable from 'formidable';
import * as fs from 'fs';
then your function like bellow:
那么你的功能如下:
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();
});
});
}
回答by vipinlalrv
Multer is a node.js middleware for handling multipart/form-data, which is primarily used for uploading files. It is written on top of busboy for maximum efficiency.
Multer 是一个用于处理 multipart/form-data 的 node.js 中间件,主要用于上传文件。它写在 busboy 之上,以实现最高效率。
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('/')
});

