Related
I tried all possible scenarios and I tried with multiple variations and approaches suggested by documentation and by other stackoverflow questions.
Any of them worked -> I keep getting req.file is: undefined
Form:
<form action="/send" enctype="multipart/form-data" method="POST">
<input type="file" id="file" name="file">
<button type="submit">Submit</button>
Express Setup:
const express = require('express');
const ejs = require('ejs');
const homeController = require('./controlers/homeController');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.set('view engine', 'ejs');
app.use(express.static('public'));
app.listen(3000);
/* routes */
app.use(homeController);
I have the following code:
var multer = require('multer')
const storage = multer.diskStorage({
destination: './public/data/uploads',
filename: function(req, file, cb) {
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
var upload = multer({
storage: storage
}).single('file');
router.get('/', (req, res) => {
res.render('home')
})
router.post('/send', (req, res) => {
upload(req, res, (err) => {
if (err) console.log(err);
console.log('req.file is: ' + req.file);
});
})
I spent 2 days trying to figure this out but I can't see the light at the end of the tunnel, and i just want to get the file from client and send it with nodemailer as attachement later on.
Answer obtained based on eMAD suggestion on question How to perform an HTTP file upload using express on Cloud Functions for Firebase (multer, busboy)
Solution below:
File is saved on the storage location you define in muller.
req.files is an array with the details of the file/files you upload.
PS: thanks #eol for pointing me in this direction
const contactControler = require('../controlers/contactController');
const busboy = require('busboy')
const express = require('express');
const router = express.Router();
var multer = require('multer');
const SIZE_LIMIT = 10 * 1024 * 1024 // 10MB
var stor = multer.diskStorage({
destination: '../public/cv',
filename: function(req, file, callback) {
callback(null, file.originalname);
}
});
const multipartFormDataParser = multer({
storage: stor,
// increase size limit if needed
limits: { fieldSize: SIZE_LIMIT },
// support firebase cloud functions
// the multipart form-data request object is pre-processed by the cloud functions
// currently the `multer` library doesn't natively support this behaviour
// as such, a custom fork is maintained to enable this by adding `startProcessing`
// https://github.com/emadalam/multer
startProcessing(req, busboy) {
req.rawBody ? busboy.end(req.rawBody) : req.pipe(busboy)
},
})
router.post('/send', multipartFormDataParser.any(), contactControler.send);
Please try adding upload in your route as middleware.
router.post('/send', upload, (req, res) => { ...
I am trying to upload files from Express ejs to AWS s3 bucket I am successful in doing so but when I am trying to select files from other directory or folder other than where my index.js is it doesn't accept the file and throw error file not found.
index.js
'use strict';
const express = require('express');
const app = express();
const multer = require('multer');
const multerS3 = require('multer-s3');
const AWS = require('aws-sdk');
const bodyParser = require('body-parser');
const s3 = new AWS.S3({
accessKeyId: '',
secretAccessKey: ''
});
app.use(bodyParser.urlencoded({extended : true}));
app.set('view engine', 'ejs');
const uploadS3 = multer({
storage: multerS3({
s3: s3,
bucket: '',
metadata: (req, file, cb) => {
cb(null, {fieldName: file.fieldname})
},
key: (req, file, cb) => {
cb(null, Date.now().toString() + '-' + file.originalname)
}
})
});
test.ejs
<html>
<form method="post" action="/upload">
<input type="file" name="file" />
<input type="submit" />
</form>
</html>
route.js
var fileupload = require('../../common/service/file-upload');
//some code in between
app.post('/upload', fileupload.uploadS3.single('file'),(req, res) => {
console.log(req.file);
});
whenever you are uploading the files you need to add attribute to form enctype="multipart/form-data". .then it will work.
to upload files to s3 use multer-s3 package which is simple to configure
Refrence : https://www.npmjs.com/package/multer-s3
so your test.ejs file will be like this
<html>
<form method="post" action="/upload" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" />
<const/form>
</html>
and index.js
const express = require('express');
const bodyParser = require('body-parser');
const AWS = require('aws-sdk');
const multer = require('multer')
const multerS3 = require('multer-s3')
const app = express();
const s3 = new AWS.S3({
accessKeyId: //aws access key ,
secretAccessKey: //aws secret key
});
const upload = multer({
storage: multerS3({
s3: s3,
bucket: 'some-bucket',
metadata: function (req, file, cb) {
cb(null, {fieldName: file.fieldname});
},
key: function (req, file, cb) {
cb(null, Date.now().toString())
}
})
})
app.post('/', upload.single('file'), (req, res) => {
res.json({
message: "File uploaded to S3"
});
});
Man, how could Express read client's file by path? The files are uploaded / sent in the POST request.
Use some body parser that support multipart/form-data file upload, like mutler, to parse the file from the request & upload it to S3.
In example...
html
<html>
<!-- don't forget enctype parameter -->
<form method="post" action="/upload" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" />
</form>
</html>
node server using AWS and multer manually
const multer = require('multer'),
AWS = require('aws-sdk'),
S3 = new AWS.S3({
...
});
router.post('/', multer().single('file'), (req, res) => {
// debug req.file
console.log(req.file);
S3.upload({
Bucket: '...',
Key: req.file.originalname,
Body: req.file.buffer
}, (err, res) => {
if (err) throw err;
res.json({
message: "File uploaded to S3"
});
});
});
node server using multer-s3
const multer = require('multer'),
multerS3 = require('multer-s3'),
AWS = require('aws-sdk'),
S3 = new AWS.S3({
...
});
let upload = multer({
storage: multerS3({
s3: s3,
bucket: '...',
key: (req, file, cb)
=> cb(null, file.originalname), // or whatever Key you like
})
});
router.post('/', upload.single('file'), (req, res) => {
res.json({
message: "File uploaded to S3"
});
});
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');
});
});
});
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.
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");
});
1) Make sure that your file is really sent from the client side. For example you can check it in Chrome Console:
screenshot
2) 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!!!');
});
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' } }
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!
Please use below code
app.use(fileUpload());
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){
...
});
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());
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');
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) {
...
}));
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 });
});
});
https://www.npmjs.com/package/formidable
You can use express-fileupload npm package to decode files like
const fileUpload = require('express-fileupload');
app.use(fileUpload({useTempFile: true}))
Note: I am using cloudinary to upload image
enter image description here
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.
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');
});
});
});
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.
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");
});
1) Make sure that your file is really sent from the client side. For example you can check it in Chrome Console:
screenshot
2) 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!!!');
});
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' } }
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!
Please use below code
app.use(fileUpload());
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){
...
});
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());
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');
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) {
...
}));
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 });
});
});
https://www.npmjs.com/package/formidable
You can use express-fileupload npm package to decode files like
const fileUpload = require('express-fileupload');
app.use(fileUpload({useTempFile: true}))
Note: I am using cloudinary to upload image
enter image description here
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.
I'm trying to upload a file into my project using multer, but I have no idea how to do it.
here's some of the code I wrote thinking it could work
// here's my ejs view
<form action="/wistia" method="post" enctype="multipart/form-data">
<input type="file" name="archivo">
<input type="submit">
</form>
// here's my route file
const multer = require("multer");
const express = require('express');
const router = express.Router();
let location = path.join(__dirname, '/uploads');
let upload = multer({ dest: location });
router.get("/wistia",function(req, res){
res.render("wistia");
});
router.post("/wistia", upload.single("archivo") , function(req, res) {
console.log(req.file);
});
thanks.
Try making this change
var upload = multer({
storage: multer.diskStorage({
destination: function (req, file, cb) {
cb(null,location);
}
})
});