I have a problem with my uploader. I think everything with code is right and still the file isnt created in uploads folder. Also when i try to console.log(req.files) i get an empty array. I try to make it locally
Here is the code:
const express = require("express"),
app = express(),
multer = require("multer"),
bodyParser=require("body-parser"),
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, './uploads/');
},
filename: function (req, file, callback) {
callback(null, file.fieldname + '-' + Date.now() + '.' + mime.extension(file.mimetype));
}
});
var upload = multer({ storage : storage }).array('userPic');
app.post("/postFormAct", isLoggedIn, function(req, res){
upload(req,res,function(err) {
console.log(req.files);
});
});
Also there is my form:
<form method="post" action="/postFormAct" enctype="multipart/form-data">
<input type="text" name="user"><br>
<input type="text" name="email"><br>
<input type="file" name="userPic"><br>
<input type="submit" value="Submit">
</form>
I think you have an issue with your function level middleware, you have isLoggedIn, you have to chain the multer middleware upload right after like so :
// ...
var upload = multer({ storage : storage }).array('userPic');
app.post("/postFormAct", isLoggedIn, upload, function(req, res){
console.log(req.files)
});
Here's a full working example :
const app = require('express')()
const bodyParser = require('body-parser')
const multer = require('multer')
const morgan = require('morgan')
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads')
},
filename: (req, file, cb) => {
cb(null, file.fieldname + '-' + Date.now())
}
})
const upload = multer({
storage: storage
})
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(morgan('dev'))
isLoggedIn = (req, res, next) => {
console.log('check if user is logged in')
next()
}
app.post('/uploads', isLoggedIn, upload.array('images'), (req, res) => {
console.log(req.files);
return res.send(req.files);
})
app.listen(8000, () => {
console.log(`server is listenning on port 8000`)
})
You can find a test repository here
Also make sure that your destination dir exist.
Instead of var upload = multer({ storage : storage }).array('userPic');
use
var upload = multer({ storage : storage }).any('userPic');
.any()
Accepts all files that comes over the wire. An array of files will be stored in req.files.
I just discovered something about Express middleware with multer.
You need to pass an array as middleware if you have more than one function that needs to act as middleware.
So this:
app.post('/uploads', isLoggedIn, upload.array('images'), (req, res) => {
console.log(req.files);
return res.send(req.files);
})
should become this:
app.post('/uploads', [upload.array('images'), isLoggedIn], (req, res) => {
console.log(req.files);
return res.send(req.files);
})
Note: Also notice that the upload middleware needs to go first...I don't know why this happens but that's the only way it worked for me.
I'm just putting this out there if anyone needs help with this(even though the question is pretty old and has an accepted answer).
Related
The problem is when I use multer and send a request in Postman the req.body comes as an empty object and the req.file comes as undefined. I've unchecked the content-type header in postman.
And here's the code:
//Route
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '../uploads/');
},
filename: function (req, file, cb) {
cb(null, new Date().toISOString() + file.originalname);
}
});
const upload = multer({
storage,
limits: {fileSize: 1024 * 1024 * 10}
});
router.post('/test', upload.single('profilePicture'), authController.test);
//Controller
const test = (req, res) => {
console.log(req.body)
console.log(req.files)
res.json({body:req.body, files:req.files})
}
//app.js
app.use(express.json({extended: true, limit: '30mb'}));
app.use(express.urlencoded({extended: true, limit: '30mb'}))
app.use(cookieParser());
app.use('/api/auth', authRoutes);
app.use('/api/product', productRoutes);
app.use('/api/profile', profileRoutes);
Edit: turnes out, the problem is in Postman. I made a request with axios from a React app and everything works. So the question is, why doesn't it work in Postman? Is it some Bug in software or is there some settings that we're supposed to change?
The problem is that Nodejs is by default uses Ansynchornus Javascript. You need to use the async-await approach and try-catch-finally methods over conventional JS programming.
So your controller would look like -
//Route
router.post('/test', async (req, res, next)=>
{
try{
await upload.single('profilePicture')
next()
} catch(err){
console.log(err)
res.send('failed!')
},
authController.test);
//Controller
const test = async (req, res) => {
try{
console.log(req.body)
console.log(req.files)
res.json({body:req.body, files:req.files})
} catch(err){
console.log(err);
}
}
A late addition to the answer.
If you're trying to just access the uploaded image, then you should make use of the buffer.
var storage = multer.memoryStorage()
var upload = multer({ storage: storage })
I'm trying to pass a file from my Angular app to a node.js server.
When I run the app, I get the following error:
Error: Please choose files
HTML:
<upload name="fileUpload" formControlName="fileUpload" #fileUpload (listChange)="updateList($event)" data-kind="primary"
[imagePreview]="true">
</upload>
Here is my updateList() method:
updateList(list: any) {
this.demolist = Array.apply(this, list);
this.attachmentReady.emit(this.demolist);
}
Node:
const express = require('express')
const app = express()
const bodyParser = require('body-parser')
const multer = require('multer');
let nodemailer = require('nodemailer');
let aws = require('aws-sdk');
const fs = require('fs');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname))
}
});
var upload = multer({ storage: storage });
app.post('/postData', upload.array('fileUpload', 12), (req, res, next) => {
console.log(req.body);
res.json(req.body);
const files = req.files
if (!files) {
const error = new Error('Please choose files')
error.httpStatusCode = 400
return next(error)
}
res.send(files);
}
In a different project, multer is working as expected. Below is the HTML from that project:
<form action="/uploadmultiple" enctype="multipart/form-data" method="POST">
Select images: <input type="file" name="myFiles" multiple>
<input type="submit" value="Upload your files" />
</form>
The difference between my working code & the code that isn't working is that I'm able to use a standard input control if the type is file.
But I need to use an upload control now & my code isn't working when I make that one change.
Can someone please tell me how I can use this control to pass the file? Thanks a lot in advance!
After you have installed multer using npm install --save multer
Basic usage example:
var express = require('express')
var multer = require('multer')
var upload = multer({ dest: 'uploads/' })
var app = express()
app.post('/uploadmultiple', upload.single('myFiles'), function (req, res, next) {
// req.file is the `myFiles ` file
// req.body will hold the text fields, if there were any
})
app.post('/uploadmultiple', upload.array('myFiles', 12), function (req, res, next) {
// req.files is array of `photos` files
// req.body will contain the text fields, if there were any
})
For more information you can read documentation here
It simply doesn't save anything to the destination folder i specified.
i tried {storage:storage} instead of {dest: 'storage/'} but it didn't work either.
the image data is actually sent to the server as its console logged. and the dest i specified is created by default but remain empty.
const express = require('express');
const app = express();
const multer = require('multer');
let storage = multer.diskStorage({
destination: '/public/my-uploads',
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
});
const upload = multer({dest:'storage/'}).single('file');
app.post('/upload', upload, (req , res) => {
console.log(req.files) // this does log the uploaded image data.
})
***** EDIT ******
HTML
<form onSubmit={this.upload} enctype='multipart/form-data'>
<input type='file' name='image' />
<input type='submit' value='upload' />
</form>
JS
upload(e){
e.preventDefault();
const file = e.target[0].files[0];
console.log(file)
const fm = new FormData();
fm.append('file', file);
console.log(fm)
axios.post('/upload', fm);
}
POSTMAN
Try to catch the error my calling the middleware yourself:
var upload = multer().single('avatar')
app.post('/upload', function (req, res) {
upload(req, res, function (err) {
if (err) {
// An error occurred when uploading
return
}
// Everything went fine
})
})
Also, change the storage to this:
let storage = multer.diskStorage({
destination: function(req, file, ca) {
cb(null, '/public/my-uploads');
}
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
});
It's been a while, the issue was that I wasn't using the multer middleware at all so the callback code for handling the image was never executed.
I didn't know much about how express worked back then.
Seems you are not using the storage variable and use a function for the destination key, as written in the documentation, also you need to pass your file in the input field named field otherwise multer can't store the file, create an storage folder on the same level as the code :
const http = require('http')
const port = 3000
const express = require('express');
const app = express();
const multer = require('multer');
const server = http.createServer(app)
let storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './storage')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
});
const upload = multer({ storage }).single('file');
app.post('/upload', upload, (req, res) => {
console.log(req.files) // this does log the uploaded image data.
})
// bind the server on port
server.listen(port, (err) => {
if (err) {
return console.log('something bad happened', err)
}
console.log(`server is listening on ${port}`)
})
The name of the "single" in ...single('file') must match the name in the input (containing the file) <input type="file" name='image' /> - and it does not in your example.
Change the multer-part to this ...single('image') - as in the input name='image'
Try this File Storage For Save image in Local
const fileStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "images");
},
filename: (req, file, cb) => {
cb(
null,
new Date().toISOString().replace(/:/g, "-") + "-" + file.originalname
);
},
});
i'm using multer to get a file from this form
<form action="/api/pimage" method="POST" enctype="multipart/form-data">
<fieldset>
<input type="file" name="profileimage">
<input type="submit">
</fieldset>
</form>
using this serverside script
app.post('/api/pimage', function(req, res, next) {
console.log(req.body, req.files);
});
the problem is that req.body is printing out { profileimage: 'image.png' }
and req.files is printing out {}
where you see the problem?
thanks
P.S. i'm using app.use(bodyParser.urlencoded({ extended: false })); to get req.body and app.use(multer({ dest: './uploads/'})); for req.files
I found that using multer alongside bodyParser can cause req.file to be undefined. Make sure to check that also if you're having issues.
I put MY (there are many I imagine and surely better) solution to help many people like me because I have searched during 1 entire day ;-(
var express = require('express');
var fileUpload = require('express-fileupload');
var fs = require("fs");
var app = express();
console.log('étape 0');
app.use(express.static('mesStatic'));
app.use(fileUpload());
console.log('étape 1');
app.get('/indexFileUpload.htm', function (req, res) {
res.sendFile( __dirname + "/" + "indexFileUpload.htm" );
})
console.log('étape 2');
app.post('/file_upload', function (req, res) {
console.log('étape 3');
console.log('req.files:' , req.files);
if (!req.files) {
res.send('No files to upload.');
return;
}
console.log('req.files.file.data:' , req.files.file.data);
var bufDataFile = new Buffer(req.files.file.data, "utf-8");
console.log('étape 3.1');
console.log('__dirname : ' + __dirname);
fs.writeFile(__dirname + '/file_upload/output.txt', bufDataFile, function(err) {
if (err) {
return console.error(err);
}
else {
console.log("Data written successfully !");
}
console.log('étape 4');
res.end('Fin OK !!!');
})
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port);
})
You have to provide your upload function defined for multer before asking for req.file in function(req, res), you can follow the code given below
var Storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, "./images/");
},
filename: function (req, file, callback) {
callback(null, file.fieldname + '_' + Date.now() + '.jpg');
}
});
var upload = multer({ storage: Storage }).single('imagePath');
router.post('/file_upload', upload, function(req, res, next){
console.log(req.file);
var Storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, "./public/images/");
},
filename: function (req, file, callback) {
callback(null, file.fieldname + '_' + Date.now() + '.jpg');
}
});
var upload = multer({ storage: Storage }).single('imagePath');
router.post('/add-product', upload, function(req, res, next){
var newProduct = new Product();
}
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.