File uploading with Express 4.0: req.files undefined
node.jsExpressnode.js Problem Overview
I'm attempting to get a simple file upload mechanism working with Express 4.0 but I keep getting undefined
for req.files
in the app.post
body. Here is the relevant code:
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
//...
app.use(bodyParser({ uploadDir: path.join(__dirname, 'files'), keepExtensions: true }));
app.use(methodOverride());
//...
app.post('/fileupload', function (req, res) {
console.log(req.files);
res.send('ok');
});
.. and the accompanying Pug code:
form(name="uploader", action="/fileupload", method="post", enctype="multipart/form-data")
input(type="file", name="file", id="file")
input(type="submit", value="Upload")
Solution
Thanks to the response by mscdex below, I've switched to using busboy
instead of bodyParser
:
var fs = require('fs');
var busboy = require('connect-busboy');
//...
app.use(busboy());
//...
app.post('/fileupload', function(req, res) {
var fstream;
req.pipe(req.busboy);
req.busboy.on('file', function (fieldname, file, filename) {
console.log("Uploading: " + filename);
fstream = fs.createWriteStream(__dirname + '/files/' + filename);
file.pipe(fstream);
fstream.on('close', function () {
res.redirect('back');
});
});
});
node.js Solutions
Solution 1 - node.js
The body-parser
module only handles JSON and urlencoded form submissions, not multipart (which would be the case if you're uploading files).
For multipart, you'd need to use something like connect-busboy
or multer
or connect-multiparty
(multiparty/formidable is what was originally used in the express bodyParser middleware). Also FWIW, I'm working on an even higher level layer on top of busboy called reformed
. It comes with an Express middleware and can also be used separately.
Solution 2 - node.js
Here is what i found googling around:
var fileupload = require("express-fileupload");
app.use(fileupload());
Which is pretty simple mechanism for uploads
app.post("/upload", function(req, res)
{
var file;
if(!req.files)
{
res.send("File was not found");
return;
}
file = req.files.FormFieldName; // here is the field name of the form
res.send("File Uploaded");
});
Solution 3 - node.js
-
Make sure that your file is really sent from the client side. For example you can check it in Chrome Console: screenshot
-
Here is the basic example of NodeJS backend:
const express = require('express'); const fileUpload = require('express-fileupload'); const app = express();
app.use(fileUpload()); // Don't forget this line!
app.post('/upload', function(req, res) { console.log(req.files); res.send('UPLOADED!!!'); });
Solution 4 - node.js
It looks like body-parser
did support uploading files in Express 3, but support was dropped for Express 4 when it no longer included Connect as a dependency
After looking through some of the modules in mscdex's answer, I found that express-busboy
was a far better alternative and the closest thing to a drop-in replacement. The only differences I noticed were in the properties of the uploaded file.
console.log(req.files)
using body-parser (Express 3) output an object that looked like this:
{ file:
{ fieldName: 'file',
originalFilename: '360px-Cute_Monkey_cropped.jpg',
name: '360px-Cute_Monkey_cropped.jpg'
path: 'uploads/6323-16v7rc.jpg',
type: 'image/jpeg',
headers:
{ 'content-disposition': 'form-data; name="file"; filename="360px-Cute_Monkey_cropped.jpg"',
'content-type': 'image/jpeg' },
ws:
WriteStream { /* ... */ },
size: 48614 } }
compared to console.log(req.files)
using express-busboy (Express 4):
{ file:
{ field: 'file',
filename: '360px-Cute_Monkey_cropped.jpg',
file: 'uploads/9749a8b6-f9cc-40a9-86f1-337a46e16e44/file/360px-Cute_Monkey_cropped.jpg',
mimetype: 'image/jpeg',
encoding: '7bit',
truncated: false
uuid: '9749a8b6-f9cc-40a9-86f1-337a46e16e44' } }
Solution 5 - node.js
multer is a middleware which handles “multipart/form-data” and magically & makes the uploaded files and form data available to us in request as request.files and request.body.
installing multer :- npm install multer --save
in .html file:-
<form method="post" enctype="multipart/form-data" action="/upload">
<input type="hidden" name="msgtype" value="2"/>
<input type="file" name="avatar" />
<input type="submit" value="Upload" />
</form>
in .js file:-
var express = require('express');
var multer = require('multer');
var app = express();
var server = require('http').createServer(app);
var port = process.env.PORT || 3000;
var upload = multer({ dest: 'uploads/' });
app.use(function (req, res, next) {
console.log(req.files); // JSON Object
next();
});
server.listen(port, function () {
console.log('Server successfully running at:-', port);
});
app.get('/', function(req, res) {
res.sendFile(__dirname + '/public/file-upload.html');
})
app.post('/upload', upload.single('avatar'), function(req, res) {
console.log(req.files); // JSON Object
});
Hope this helps!
Solution 6 - node.js
Please use below code
app.use(fileUpload());
Solution 7 - node.js
Just to add to answers above, you can streamline the use of express-fileupload
to just a single route that needs it, instead of adding it to the every route.
let fileupload = require("express-fileupload");
...
//Make sure to call fileUpload to get the true handler
app.post("/upload", fileupload(), function(req, res){
...
});
Solution 8 - node.js
A package installation needs for this functionality, There are many of them but I personally prefer "express-fileupload". just install this by "npm i express-fileupload" command in the terminal and then use this in your root file
const fileUpload = require("express-fileupload");
app.use(fileUpload());
Solution 9 - node.js
PROBLEM SOLVED !!!!!!!
Turns out the storage
function DID NOT run even once.
because i had to include app.use(upload)
as upload = multer({storage}).single('file');
let storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './storage')
},
filename: function (req, file, cb) {
console.log(file) // this didn't print anything out so i assumed it was never excuted
cb(null, file.fieldname + '-' + Date.now())
}
});
const upload = multer({storage}).single('file');
Solution 10 - node.js
I added multer as global middleware before methodOverride middleware, and it worked in router.put as well.
const upload = multer({
storage: storage
}).single('featuredImage');
app.use(upload);
app.use(methodOverride(function (req, res) {
...
}));
Solution 11 - node.js
With Formidable :
const formidable = require('formidable');
app.post('/api/upload', (req, res, next) => {
const form = formidable({ multiples: true });
form.parse(req, (err, fields, files) => {
if (err) {
next(err);
return;
}
res.json({ fields, files });
});
});
Solution 12 - node.js
express-fileupload
looks like the only middleware that still works these days.
With the same example, multer
and connect-multiparty
gives an undefined value of req.file or req.files, but express-fileupload
works.
And there are a lot of questions and issues raised about the empty value of req.file/req.files.