Cannot app.use(multer). "requires middleware function" error - node.js

I'm just starting learning NodeJS and I am stuck with a problem. I would like to upload files to my server. To do so I searched and found out this module multer. Doing as the example on GitHub works:
var express = require('express');
var multer = require('multer');
var upload = multer({ dest: 'uploads/' });
var app = express()
app.post('/uploadImage', upload.single('image'), function(req, res) {
console.log(req.file);
});
On posting an image with FormData to /uploadImage the image is saved in the uploads/ directory. The thing is the image is saved with a strange name and I would like to save it with its original name.
To do so I understood that I would have to call app.use(multer({ dest: 'uploads/' }))' and then I would be able to access req.file in my function like:
app.post('/uploadImage', function(req, res) {
console.log(req.file);
});
But I get an error on trying app.use():
TypeError: app.use() requires middleware functions
at EventEmitter.use (project\node_modules\express\lib\application
.js:209:11)
Im using NodeJS 0.12.7 and Express 4.13.1
How can I achieve that upload? Thanks.

You need to use app.use(multer({dest:'./uploads/'})) in the form of one of these:
app.use(multer({dest:'./uploads/'}).single(...));
app.use(multer({dest:'./uploads/'}).array(...));
app.use(multer({dest:'./uploads/'}).fields(...));
ie:
app.use(multer({dest:'./uploads/'}).single('photo'));
And be sure to have something like:
<form action="/postPhotos" enctype="multipart/form-data" method="post">
<input type="file" name="photo">
<input type="submit" value="Upload photo">
</form>
In your html.

var app = require('express');
var multer = require('multer');
app=express();
app.use(multer({dest:__dirname+'/file/uploads/'}).any());
app.post('/upload',function(req,res){
console.log(req.files);
res.redirect('/');
});

The answer from #127.0.0.1 is correct, but in case you are using Express Router, the code changes a little bit:
var express = require('express');
var multer = require('multer');
var router = express.Router();
var uploads = multer({
dest: 'public/uploads/'
});
router.post('/upload', uploads.single('avatar'), function(req, res, next) {
console.log(req.file);
//...
});
And the important bit, the form encoding should be enctype="multipart/form-data" as already said, like that:
<form action="/upload" enctype="multipart/form-data" method="post">
<input type="file" name="avatar">
<input type="submit" value="Go avatar go!">
</form>

You can't change the file name using multer but you can use Node.js stream and fs module to copy the content of already uploaded file to new file(set as original file name) on same folder and delete old one.
First of all import fs, path and multer in your node script.
var express = require('express');
var multer = require('multer');
var fs = require('fs');
var pathModule = require('path');
Now, set destination directory of any type of files using multer as below.
var app = express();
app.use(multer({dest:__dirname+'/resoucres/'}).any());
Now use stream and fs to resolve your issue.
app.post('/uploadImage', function(request, response) {
var readerStream = fs.createReadStream(request.files[0].path);
var dest_file = pathModule.join(request.files[0].destination, request.files[0].originalname);
var writerStream = fs.createWriteStream(dest_file);
var stream = readerStream.pipe(writerStream);
stream.on('finish', function(){
fs.unlink(request.files[0].path);
});
});

Since version 1.0.0
var upload = multer({ dest: 'tmp/' });
app.post('/file_upload', upload.single('photo'), function (req, res) {

Changing to app.use(multer({dest:'./uploads/'}).single('photo')); in the app.js works for me to start the server

I encountered the same problem. And I solved it.
For the first problem, how to get the original file name?
I printed the whole request and found we could get original name by using the path
"req.file.originalname"
and the other question, how to use "app.use()"?
refers: here

Related

How to access body parameters while using multipart form data in NodeJS

There were lots of similar questions related to mine, but no one gonna clear my doubt.
So,whenever I write
<form id="form" action="/" method="post" role="form">
and in my backend code, Let say I write
console.log(req.body.name)
I got the data correctly, but if I add enctype = multipart/form-data as
<form id="form" action="/" method="post" role="form" enctype="multipart/form-data">
I got req.body.name as 'undefined' or body parameters as 'undefined'.
Is there any way to get the body parameters While using enctype="multipart/form-data?
Please Help!
enctype="multipart/form-data" is not natively handled by express, you can use multer to handle multipart/form-data
npm install --save multer
Multer NPM
const multer = require('multer');
let upload = multer({ dest: 'uploads/' }); //<-- Could be any folder
router.post('/', upload, function (req, res) {
console.log('Body- ' + JSON.stringify(req.body));
});
In an alternative way, you can use a formidable module from the NPM.
Npm formidable
npm install --save formidable
const multer = require('formidable');
router.post('/', upload, function (req, res) {
const form = formidable({ multiples: true });
form.parse(req, (err, fields, files) => {
console.log('fields: ', fields);
console.log('files: ', files);
// enter code here
});
});

req.file always undefined using multer in my Node express application

I tried to upload image file from client side to my AWS S3 storage server using multer with the support of multer-s3. However, I keep getting undefined result for my req.file call. I have been googling and check all possible causes to my problem and no luck so far. Hope someone can help me here. Thanks in advance.
Client side HTML code:
<form method="post" enctype="multipart/form-data" action="/create">
<input type="text" name="name" />
<input type="text" name="topic" />
<input type="file" name="image" />
<input type="submit" value="Upload" />
</form>
Server side code:
var express = require('express');
var http = require('http');
var app = express();
var methodOverride = require('method-override');
var bodyParser = require('body-parser');
var multer = require('multer');
var multerS3 = require('multer-s3');
var AWS = require('aws-sdk');
app.use(methodOverride());
app.use(bodyParser.urlencoded({ extended: true }));
//Create S3 client
var s3 = new AWS.S3();
//this code is copy directly from multer-s3 since I don't care about my file name shown on S3 for now
var upload = multer({
storage: multerS3({
s3: s3,
bucket: mybuckname,
metadata: function (req, file, cb) {
cb(null, {fieldName: file.fieldname});
},
key: function (req, file, cb) {
cb(null, Date.now().toString())
}
})
});
app.post('/create', upload.single('image'), function(req, res) {
var nameField = req.body.name,
topicField = req.body.topic;
console.log("File: ", req.file);
console.log("Name: ", nameField);
console.log("Topic: ", topicField);
res.sendStatus(200);
res.end();
});
I have tried the following:
Removed 'body-parser' and use 'multer' only, then even worse result (both req.body and req.file are undefined). With body-parser, at least I can guarantee req.body is working
To simplify the cause, I removed all my text field inputs from client side and leave only file upload option to make sure I am only transmitting file data, still return undefined for req.file (multer is not working at all)
I also read about the possibility that "Note that req.body might not have been fully populated yet. It depends on the order that the client transmits fields and files to the server." In my case, I am not getting the file so it doesn't matter for me now.
Use multer only without multer-s3, and tried upload.array instead of upload.single, still no luck (multer-s3 is built on top of multer, so I don't think it has anything to do with my current problem, but just to give it a try)
Skip AWS S3 and store it in local path, still undefined result
after long struggle switching between multer and busboy and nothing works. All the sudden I noticed my form is actually using a Polymer element 'is="iron-form"' which my mistake didn't type it in my original post as shown below. After removed it, my file upload is working on multer - I'm sure it will also work on busboy.
<form is="iron-form" method="post" enctype="multipart/form-data" action="/create">
Polymer elements always create problems to me in the past. But don't take me wrong, it's a great project with many great things available to design your page. But you need to really understand how to use those elements to take the advantage of them. In my case, I learn from my lesson and hope to share it with you.

Unzip file is not working

Im using the following code from
https://github.com/cthackers/adm-zip/wiki/ADM-ZIP-Introduction
Whant I need is to get a zip file from request(Im using express and I've request and response) and I need to extract(unzip) it to some path(in the example for my local drive) ,where should I put the req and what Im missing here to make it work
fn: function (req, res) {
var admZip = require('adm-zip');
var zip = new admZip();
zip.addLocalFile("C://TestFolder//TestZip");
in the request body im getting the zip file(im using postman and in the body I use the binary and select a zip file)
Please try my snippet code :
For some information, My App structure like this below :
my path --> C:\xampp\htdocs\service
service
|
-- tmp\
|
-- app.js
|
-- index.html
Client Side:
<html>
<body>
<h3>ZIP Upload:</h3>
<form action="/upload_zip" method="POST" enctype="multipart/form-data">
Select zip to upload:
<input type="file" name="zipFile" id="zipFile">
<input type="submit" value="Upload ZIP" name="submit">
</form>
</body>
</html>
Server Side:
Don't forget using enctype="multipart/form-data" when you post it using postman or something like that...
var express = require("express");
var fs = require("fs");
var AdmZip = require('adm-zip');
var app = express();
var multer = require("multer");
var multer_dest = multer({dest: "./tmp"}).single('zipFile');
app.get("/",function(req,res){
console.log("Show index.html");
res.sendFile(__dirname+"/"+"index.html");
});
app.post("/upload_zip",multer_dest,function(req,res){
console.log(req.file);
var zip = new AdmZip(req.file.path);
zip.extractAllTo("./tmp");
result = {
file:req.file,
message:"File has been extracted"
};
fs.unlink(req.file.path, function (e) {
if (e) throw e;
console.log('successfully deleted '+req.file.path);
});
res.end(JSON.stringify(result));
});
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);
})
Output :
You could simplify the problem by using form-data instead of binary and using multer. You can get the input file by accessing req.file after which you can perform your unzip operation.
For example, you would add to your route:
var upload = require('multer')({ dest: 'uploads/' });
var admZip = require('adm-zip');
app.post('/upload-here', upload.single('file'), function (req, res, next) {
var zip = new admZip(req.file.path);
zip.extractAllTo("C://TestFolder//TestZip", true);
});

Cannot POST using node & Express (Jade, MongoDB, Express, Node)

I have a form in which a user can select a .xlsx file and upload it:
p Upload New Schedule
#uploadNew
form(id = "form1", action="/uploadNew", method="post", enctype="multipart/form-data")
input(type="file", id="control", name="XLupload")
br
input(type="submit" value="Upload" name="Submit")
in my main app.js I have this route to deal with it.
var uploads = require('./routes/upload');
//Make the db accessible to various http requests
app.use(function(req, res, next) {
req.db = dbMain;
next();
});
app.use('/', routes);
app.use('/upload', uploads);
and In my upload.js file I have the following:
var xlsx = require('xlsx');
var multer = require('multer');
var upload = multer({dest: './uploads'});
var excel_upload = upload.single('XLupload');
router.get('/upload', stormpath.groupsRequired(['Enforced']), function(req, res) {
res.render('upload', {
title: 'Uploading Excel File'
});
next();
});
router.post('/upload', excel_upload, function(req, res) {
// Get the path to the uploaded Excel file
var fileObject = req.file;
var filePath = fileObject.path;
// Get collection instance which will store the data from the newly posted schedule
var dbLocal = req.db;
var insertionCollection = dbLocal.collection('chip');
.....
However, when I start up and listen at localhost, when I select a file and try to upload I get error cannot POST /upload. When I did not have routes and had everything in the main app.js file, this was not an issue. What did I mess up by introducing routes?
This:
app.use('/upload', uploads);
Combined with this:
router.post('/upload', ...)
Declares this route: POST /upload/upload
If you mount a router (using app.use(PATH, router)), PATH adds a prefix to all the routes handled by that router. Your router need to declare routes relative to that prefix:
router.post('/', ...)

node.js upload with multer not working

I am trying to implement file uploads with node.js and the multer middleware, but it doesn't seem to work. This is my code:
var express = require('express');
var multer = require('multer');
var done = false;
var app = express();
app.use(multer( {dest:'./uploads/',
onFileUploadStart : function(file){
console.log('File recieved:');
console.log(file);
},
onFileUploadData:function (file,data){
console.log('Data recieved');
},
onParseEnd: function(req,next){
next();
}
}));
app.use(express.static(__dirname+"/public"));
app.post('/upload',require(__dirname+'/upload.js').upload);
app.listen(3000);
My form looks like this:
<html>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name ="file">
<input type="submit" value="Upload selected file to server">
</form>
</body>
</html>
And upload.js looks like this:
exports.upload = function (req,res)
{
console.dir(req.files);
};
I think the problem is that my form is being submitted with "application/x-www-form-urlencoded" in the Content-Type header instead of "multipart/form-data", since this is what appears when I use Fiddler to monitor the request, but I have no idea why. Can anyone shed any light on this?
I got it working by adding an accept attribute to my tag in my html. I don't know why in some examples this is not used.
Here's the code for my entire form:
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name ="file" accept="application/x-zip-compressed,image/*">
<input type="submit" value="Upload selected file to server">
</form>
Check the entire project eventually: https://github.com/tutiplain/quickupload
I can see you are doing everything right. I used multer sometime back, you can look into my working implementation here. In this EJS file i have an image upload functionality and then i wrote some logic to store the file to some other location.
Make sure you have appropriate router, for example you can use router.post(..)
exports.upload= function(req,res){
// get the temporary location of the file
var tmp_path = req.files.file.path;
// set where the file should actually exists - in this case it is in the "images" directory
var target_path = '/..provide path to store photos../' + req.files.file.name;
// move the file from the temporary location to the intended location
fs.rename(tmp_path, target_path, function(err) {
if (err) throw err;
// delete the temporary file, so that the explicitly set temporary upload dir does not get filled with unwanted files
fs.unlink(tmp_path, function() {
if (err) {
throw err;
}else{
//response logic ...
};
});
});
};
You can try this. It works for me. If any issues then let me know
var multer = require('multer');
var upload = multer({ dest: './uploads' });
router.post('/register',upload.single('profileimage'),function(req,res,next){
if (req.file) {
console.log('Uploading File');
var profileImageOriginlName=req.file.originalname;
var profileImageName=req.file.name;
var profileImageMime=req.file.mimetype;
var profileImagePath=req.file.path;
var profileImageExt=req.file.extension;
var profileImageSize=req.file.size;
}
else
{
var profileImageName='noimage.png';
}
});

Resources