Configuring multer to upload files to nodejs server - node.js

The express Router is setup as such:
var router = require('express').Router();
var multer = require('multer');
var uploading = multer({
dest: './uploads/',
limits: {fileSize: 1000000, files:1},
});
router.post('/upload', uploading.single('avatar'), function(req, res) {
console.log('success');
});
module.exports = router;
I am attempting to upload files:
curl -F "image=#/Users/runtimeZero/Desktop/nassau.jpg" localhost:3000/auth/upload
The express server throws the below error:
Error: Unexpected field
at makeError (/Users/.../node_modules/multer/lib/make-error.js:12:13)
at wrappedFileFilter (/Users/../node_modules/multer/index.js:39:19)
...
...
at HeaderParser.push (/Users/.../node_modules/multer/node_modules/busboy/node_modules/dicer/lib/HeaderParser.js:46:19)
at Dicer._oninfo (/Users/.../node_modules/multer/node_modules/busboy/node_modules/dicer/lib/Dicer.js:197:25)
From multer documents this seems pretty straight forward. However, not so much when actually using it. What am i missing ?

If you look at the multer readme you will see that multer() returns an object that contains various functions that return different middleware, depending on your needs.
For example, to accept a single file whose name is 'avatar':
var upload = multer({dest: './uploads/'});
router.post('/upload', upload.single('avatar'), function(req, res) {
console.log('success');
});

Related

Upload a image with other key-value parameters to postman in NodeJS/Express

I'm new to NodeJS and I tried this to post images through postman.
But I can't figure out where am I lacking?
The postman parameters :
NodeJS Code
Now to access these values in my NodeJS, I'm currently doing this :
var express = require('express');
var bodyParser = require('body-parser');
const router = express.Router();
router.use(bodyParser.json());
router.post('/postData/uploadStory', function(req, res) {
console.log(req.files);
console.log(req.body);
res.json("Hi");
})
How can I get access to the image and the key-value?
Also looked at express-fileupload node-module for doing this work for me.
Created a simple ejs with input name=foo type=file
tried to access it in the server.js file as console.log(req.files).
Didn't work.
Am I missing something? Please help. Thanks.
multer is best option to upload file in node.js
create separate folder for multer like multerHelper.js
const multer = require('multer');
let fs = require('fs-extra');
let storage = multer.diskStorage({
destination: function (req, file, cb) {
fs.mkdirsSync(__dirname + '/uploads/images'); // fs.mkdirsSync will create folders if it does not exist
cb(null, __dirname + '/uploads/images');
},
filename: function (req, file, cb) {
console.log(file);
cb(null, Date.now() + '-' + file.originalname);
}
})
let upload = multer({ storage: storage });
let createUserImage = upload.single('photo');
let multerHelper = {
createUserImage,
}
module.exports = multerHelper;
In your routes import multerhelper file
const multerHelper = require("../helpers/multer_helper");
router.post('/upload/:userid',multerHelper, function(req, res) {
console.log(req.files);
console.log(req.body);
res.json("Hi");
})

multer, npm - originalname is garbled:(

I'm creating a video upload API in Node.js. To upload it, I have to handle the multipart request, so I'm using npm library "multer".
Try to send a video file(like below) in Postman.
テスト_test.mp4
"テスト" is some Japanese character. And when posting that, the result is:
console.log(req.file.originalname)
=> ƹ�(_test.mp4
I want
originalname=>テスト_test.mp4
not
originalname=>ƹ�(_test.mp4
Implementation:
const express = require('express')
const router = express.Router()
const request = require('request')
const multer = require('multer')
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "some/dest/dir")
}
})
var upload = multer({
storage: storage
}).single("file")
router.use(upload)
router.post("/videos", functinon(req, res, next){
console.log(req.file.originalname)
})
Postman:
・request header Content-Type: multipart/form-data
・request body file:テスト_test.mp4
Does anybody have ideas?

File uploading in express using multer

I am trying to upload image using multer but getting error,uploads is not a function.Here is my code
var multer = require('multer');
var uploads = multer({dest: './images'});
app.post('/uploading', uploads.single('image'), function(req, res) {
console.log(req.file);
var file = __dirname + '/' + req.file.filename;
uploads(req.file.path, file, function(err) {
if (err) {
console.log(err);
res.send(500);
} else {
res.json({
message: 'File uploaded successfully',
filename: req.file.filename
});
}
});
var multer = require('multer');
var uploads = multer({dest: './images'});
app.post('/uploading', uploads.single('image'), function(req, res) {
yourModel.create(req.body,function(err,result){
console.log(result);
});
});
Its quite obvious; uploads is not a function but uplaod is. So use
upload.single('image')
As #Kuldeep said you don't have to the uploads(filePath, file, (err) => {...}) inside the route.
When you are using multer as middleware (the middle function) multer will automatically upload the file and expose the filename, originalName etc to req.file object inside the route
var multer = require('multer');
var uploads = multer({dest: './images'});
app.post('/uploading', uploads.single('image'), function(req, res) {
// here just write the success or error login
});
Reference You can check here: here
EDIT: The above code will upload the file with hex string as filename without any extension.
In order to add rename function you need to use diskStorage. Here is the code taken from this github issue page.
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './images/')
},
filename: function (req, file, cb) {
crypto.pseudoRandomBytes(16, function (err, raw) {
cb(null, raw.toString('hex') + Date.now() + '.' + mime.extension(file.mimetype)); //this is the rename func
});
}
});
var uploads = multer({ storage: storage });
Now you can use the uploads variable as middleware as shown in the above snippet.
I haven't found a great, soup-to-nuts guide on using Multer (the website is just a little lacking for newbies) so here's my stab at it.
After using:
npm install multer --save
to add it to your project.
For me, I wanted to capture files on a specific route, namely:
/customers/:id/upload
So, I went into my customers.js route file and added:
var multer = require('multer');
as well as the code to set up the storage (diskStorage) and filename configuration tweaks:
var storage=multer.diskStorage({
destination: function(req,file,cb){
cb(null,'/uploads/');
},
filename: function(req,file,cb){
cb(null,file.fieldname+'-'+Date.now());
}
});
I could then create the upload middleware object that lets me specify, per route, how I would like Multer to handle file uploads. On the route above, I only want to receive one file with a particular internal filename so my customers.js route file looks like this:
router.post('/:id/targets/upload', upload.single('connections'), function(req,res,next){
console.log("Router:POST: Companies/:_id/upload");
console.log(req.file);
...
});
All of the examples I saw had stuff being added to the app.js file but these seemed a bit awkward and contrived as examples. Every route may have different file handling needs so it just seemed more appropriate, to me, to configure Multer on a per-controller basis. YMMV.

Dynamically reload multer with new limits fileSize value

I'm using these lines to initialize multer:
file_size_limit=1000000;
var multer = require('multer');
upload = multer({ dest: 'upload/', limits: { fileSize: global.file_size_limit }}).array('fileUploaded');
And in the route i use for example:
router.post('/', global.upload, function(req, res, next) {
What i have already achieved with busboy is that, i can create an admin section, and change the file size limit, which restricts the size of uploaded files. There is no need to restart the server as the var busboy = ... functionality lies within the router.post('/', function(req, res, next){}) ..
I am not able to do this in multer without restarting the server.
Is it possible to re-assign upload variable with new multer settings on a given route being accessed?
Could be something like this...
router.get('/', function(req, res, next){
global.upload = multer({ dest: 'upload/', limits: { fileSize: new_file_size_limit }}).array('fileUploaded');
});
Right now all i can think of is to save the new setting of fileSize in a database and then write a .js file which would make the server restart using nodemon (which monitors code changes and restarts if any)...
Can this be done without restarting the server?
Okay, i found how to do this. For others facing this problem, i'm posting the solution here. The upload variable can be nested inside the req, res of the route. (It is not necessary that upload variable is a parameter in the route itself)
The code would look like this:
router.post('/', function(req, res, next) {
var upload = multer({ dest: 'upload/', limits: { fileSize: req.app.locals.size }}).array('myfile');
upload(req, res,function(err) {
if(err) {
return res.end(err.toString());
}
console.log(req.body);
var tmp_path = req.files[0].path;
var target_path = '/home/' + req.files[0].originalname;
fs.rename(tmp_path, target_path, function(err) {
if (err) throw err;
});
res.redirect('back');
});
});

File uploading with Express 4.0: req.files undefined

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.

Resources