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

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.

Related

Cant get the file upload functionality working with nodejs and express

I have a form with enctype set to multipart form-data which has one file upload input and there are other text input fields. I do see in the post request that the form is being sent as multi part with the uploaded file. I tried using multer and express-fileupload. Tried all different ways I could try from other stackoverflow threads related to this but I just cant get the file in req.files . Its always undefined. I am not using any middleware. I am just using body-parser which I know does not parse multi-part data. Is there an example on how to get a file upload working with other form fields using the current versions of node and express?
You can try it:
Install express and multer
npm install express multer
app.js file:
const express = require('express');
const app = express();
const multer = require('multer');
// dest -> which tells Multer where to upload the files
const upload = multer({dest:'uploads/'}).single("avatar");
app.post("/profile", (req, res) => {
upload(req, res, (err) => {
if(err) {
res.status(400).send("There is a problem!");
}
res.status(200).json({file: req.file});
});
});
app.listen(3000, () => {
console.log('Server is runnig on port 3000');
});
And run server:
node app.js
In Postman addressbar set this url: http://localhost:3000/upload-image
and you can upload file in Postman and check response.
Also you can upload file in browser without Postman.
<form action="/profile" method="post" enctype="multipart/form-data">
<input type="file" name="avatar" />
</form>
read more details: express with multer doc

How to handle binary post data in Express?

I am wanting to post an image in the form of binary to my Express app.
I'm assuming it should come through in the req.body object but will need some form of middleware to be able to handle binary data?
When I send an image as binary from postman and try log req.body, the object is empty.
I am using express-generator as a boilder plate which comes with body-parser like so:
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
I had a look at Multer but think that is just for multipart data
Also looked at busboy but couldn't figure out if that will handle binary data.
Am I correct that the post data will still come through in req.body?
And what middleware do I need to handle binary data?
Thanks
The method I ended up using:
const multer = require('multer')
const storage = multer.memoryStorage()
const upload = multer({ storage: storage })
router.post('/upload', upload.single('image'), function(req, res, next) {
const image = req.file.buffer
});
Unfortunately, you can't use the body-parser to handle the binary data like files and stuff like that. But wut you can do is use a module call formidable to handle this
Example snipper
app.post('/', (req, res) => {
const form = new formidable.IncomingForm();
form.parse(req, (error, fields, files) => {
if(error){
console.log(error)
}
console.log(fields.name)
const cuteCat = files.cat_image;
console.log(cuteCat.name) // The origin file name
console.log(cuteCat.path) // The temporary file name something like /tmp/<random string>
})
});
<input name="cat_image" type="file" />
<input name="name" type="text" />

Error in using "vaadin file upload"(polymer) via nodejs with express

I am trying to upload a simple file using the vaadin file upload element(refer https://vaadin.com/elements/-/element/vaadin-upload)
I am using nodejs and express with multer as middle-ware on the server side.
The nodejs simplified code is as follows:
var express = require("express");
var multer = require('multer');
var app = express();
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, './uploads');
},
filename: function (req, file, callback) {
callback(null, file.fieldname + '-' + Date.now());
}
});
var upload = multer({ storage : storage}).single('userPhoto');
app.get('/',function(req,res){
res.sendFile(__dirname + "/index.html");
});
app.post('/api/photo',function(req,res){
upload(req,res,function(err) {
if(err) {
return res.end("Error uploading file.");
}
res.end("File is uploaded");
});
});
I tried with an HTML element in my index.html and this code works
<form id = "uploadForm"
enctype = "multipart/form-data"
action = "/api/photo"
method = "post"
>
<input type="file" name="userPhoto" />
<input type="submit" value="Upload Image" name="submit">
</form>
But I want to use the vaadin upload element. I wrote the code
<link rel="import" href="../bower_components/vaadin-upload/vaadin-upload.html">
<vaadin-upload id="userPhoto" target="/api/photo"></vaadin-upload>
When I use this, it does not work as expected. I am able to see the vaadin element. But I am unable to upload a file. As I select the file, the server responds with the string 'Error uploading file'. I am pretty new to polymerjs and web development. Could someone please point me where I am going wrong?
In your backend code, you have to change the file parameter name from 'userPhoto' to 'file'.
In case of the native HTML form, it sends a file in the parameter declared by the name attribute of the <input type="file">.
When using the Vaadin Upload element, the files are sent in the same manner as by the HTML form. But instead of the provided name, they are sent in the parameter called "file".
Note that you have the id="userPhoto" attribute for the upload. The id is a different attribute, that does not act like a name.
Unfortunately, the file parameter name for the upload requests cannot be easily customized for now. We are planning to add more upload request customization features in future.

Nodejs multipart/form-data dont let upload files

Problem
I have a server that needs to upload files, I have tried multiparty, connect-multiparty and multer.
But every case, has the same problem: the file only uploads some times, i mean, i could send a file and there is a chance that the libraries don't parse the files, and never continue the code, resulting on not uploading the files.
In a While, the request send an error "Request Aborted", but its the normal response when the request time out
This is the problematic node.js file:
var multiparty = require('multiparty');
var multer = require('multer');
var upload = multer({
dest: "/uploads/"
});
///----rest of code----
//1. Multiparty
app.post("/upload",[function(req, res){
var form = new multiparty.Form({uploadDir:'/uploads/'});
console.log("to upload")
form.parse(req, function (err, fields, files) {
console.log("uploaded");
res.json({uploaded: true});
})
}]
//2. multer
app.post("/upload2",[
function(req, res, next){
console.log("to upload");
next();
},
upload.fields([
{name: "file"},
{name: "thumbnail"}
]),
function(req, res){
console.log("uploaded");
res.json({uploaded: true});
}]
Make sure your form looks like this
<form enctype="multipart/form-data" action="..." method="...">
...
</form>
And to be honest you will be better off using node-formidable. It is the most used multipart/form-data package on npm.
The example works straight out of the box.
Cheers
https://stackoverflow.com/a/23975955/4920678
I was using the setup from this answer, to use http and https over the same Port.
Turns out, the setup with that proxy damaged the packages that where too large or something, and then the files never get parsed

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

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

Resources