file upload error in node.js - node.js

To upload a file in node.js express I am using multer module. The code itself in a separate file is working like charm. but if I place the same code in my project(html code in one file and routing in another file) its not working.
Html code:
<form method="post" action="uploadgallerypic" enctype="multipart/form-data" >
<input type="file" name="gallerypic" />
<input type="submit" value="upload" />
</form>
corresponding routes.js code
app.use(multer({ dest: './uploads'}));
app.post('/uploadgallerypic', function(req, res) {
console.log("New photo added");
console.log(req.files);
fs.readFile(req.files.gallerypic.path, function(err, data) {
if(err) {
console.log("Error in reading pic from disk");
}
else {
fs.writeFile('newpic.jpg', data, 'binary', function(err) {
console.log("Error in writing pic to disk");
});
}
});
});
After clicking on submit the very first statement console.log('New photo added') which prints to console is not executing. Browser simply rotates and finally says 'No Data received'. But If I create a single file with these two blocks then its working fine.
var express = require('express');
var multer = require('multer');
var app = express();
var form = "<form method=\"post\" action=\"uploadgallerypic\" enctype=\"multipart/form-data\" >" +
"<input type=\"file\" name=\"gallerypic\" />" +
"<input type=\"submit\" value=\"upload\" />" +
"</form>";
app.use(multer({dest:'./uploads/'}));
app.get('/', function (req, res){
res.writeHead(200, {'Content-Type': 'text/html' });
res.end(form);
});
var fs = require('fs');
app.post('/uploadgallerypic', function(req, res) {
console.log("New photo added");
console.log(req.files);
fs.readFile(req.files.gallerypic.path, function(err, data) {
if(err) {
console.log("Error in reading pic from disk");
}
else {
fs.writeFile('newpic.jpg', data, 'binary', function(err) {
if(err) {
console.log("Error in writing pic to disk");
}
});
}
});
res.redirect('/profile');
});
app.listen(8080);
please tell me what I am missing here.
Edit#1
I removed app.post('/uploadgallerypic', function(req, res) block from routes.ejs to see the error "Cannot POST /uploadgallerypic" but I am not getting such error, browser simply rotating and says no data received. If I remove the enctype='multipart/form-data' satement from html code then I am getting the exact error "Cannot POST /uploadgallerypic". Is there any problem in using enctype='multipart/form-data'.
Please help me.

I think this might be minor typos...there are at least three things in the 'broken' example that are wrong/different from your 'working' example.
1) Is the dest value good?
In your broken example, change this line:
app.use(multer({ dest: './uploads'}));
...to this:
app.use(multer({ dest: './uploads/'}));
(Note the addition of the trailing slash on the dest path. Maybe not important, but I didn't go read the multer source to see if it matters. I just know it matters in some other situations, such as with some situations with grunt.)
2) Your app.post looks off:
Change this:
app.post('/uploadgallerypic', function(err, res) {
...to this?
app.post('/uploadgallerypic', function(req, res) {
(was there a reason you had err in there?)
3) And related to #2...
From this:
fs.readFile(req.files.gallerypic.path, function(req, data) {
...to this:
fs.readFile(req.files.gallerypic.path, function(err, data) {
(So...did you copy the code around or rewrite it by hand and accidentally swap which argument goes where?)

don't directly inject multer into express.
like this way
app.use(multer({ dest: './uploads/'}));
instead
1) create object of multer
var Upload = multer({
storage: storage
}).any('gallerypic');
2) create storage for gallerypic (upload file )
// storage for upload file.
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, './file');
},
filename: function (req, file, callback) {
callback(null, file.originalname);
}
});
3) define your route
router.post('/uploadgallerypic', postData);
4) Invoke multer in your route.
function postData(req,res){
Upload(req, res, function (error) {
if (error) {
res.status(400).send(error);
}
console.log("New photo added");
console.log(req.files);
fs.readFile(req.files.gallerypic.path, function(err, data) {
if(err) {
console.log("Error in reading pic from disk");
}
else {
fs.writeFile('newpic.jpg', data, 'binary', function(err) {
if(err) {
console.log("Error in writing pic to disk");
}
});
}
});
res.redirect('/profile');
})
}
refer this like : How to return id of uploaded file (upload with multer in nodejs express app)

Related

Can't parse form-data twice

What I am trying to do is delete the images with same id before I upload a new image, if the user has inputed image. Multer does not provide a way to detect if there is an input only, it has to upload the file first.
So I figured out to use another form-data libarary to do just that. But when I do that multer doesn't recieve the form-data to upload. So it doesn't upload anything. The image only get delete, but no new images are added.
The problem is I can't parse for data twice. How can i fix it? Or is there a workaround?
Code explination
I am using multyparty to detect if the user has included an image in a form.
form.parse(req, async (err, fields, files) => {
if (err) console.log(err);
else if (files.image) removeImagesWithSameId(req.params.id)
});
If there an image in the form then delete the previous uploaded image
const removeImagesWithSameId = (id) => {
fs.unlink(__dirname + id + ".jpg", (err) => {
if (err) console.log(err)
console.log("image Delete")
})
}
Then upload the new image, using multer.
upload(req, res, (err) => {
if (err) console.log(err)
else if (req.file) console.log("Image uploaded")
});
Execpt the new image not getting uploaded, because multer not receiving the data and req.file is undefined.
My questions is why multer is not receiving the data when ever I add multiparty, and how to fix it?
Whole the code
const express = require('express');
const app = express();
const multiparty = require('multiparty');
const form = new multiparty.Form();
var upload = multer({ dest: __dirname }).single('image');
const removeImagesWithSameId = (id) => {
fs.unlink(__dirname + id + ".jpg", (err) => {
if (err) console.log(err)
console.log("image Delete");
})
}
app.post('/upload/:id', (req, res) => {
form.parse(req, async (err, fields, files) => {
if (err) console.log(err);
else if (files.image) removeImagesWithSameId(req.params.id)
});
upload(req, res, (err) => {
if (err) console.log(err)
else if (req.file) console.log("Image uploaded")
});
})
Note this is only demonstration of the probelm. My actaul code is bit longer then that.
For people who is asking about the requst, I am using nodemon, but this equivalent curl requst.
curl --location --request PUT 'localhost/upload/1593735936343' \
--form 'image=#/C:/Users/Hamza/images/test.jpg'

Upload and redirect page using multer

I am having a problem to redirect the page after a successful file upload using multer. With the file upload i am also saving some text into the database. Here's my code.
Question :
When the file and the contents are saved in the DB how can I redirect the page to a new URL ?
I am currently using res.redirect('product/item'); but nothing happens. I also tried using res.render, but the page did not redirect.
Multer method to upload a file to Amazon S3
var upload = multer({
storage: multerS3({
s3: s3,
bucket: 'nameofthebucket',
metadata: function (req, file, cb) {
var ext = file.originalname.split('.').pop();
cb(null, {fieldName: 'file.fieldname' + '.' + ext});
},
filename: function(req,file,cb){
var ext = file.originalname.split('.').pop();
cb(null, Date.now() + '.' + ext);
},
key: function (req, file, cb) {
var ext = file.originalname.split('.').pop();
cb(null, Date.now() + '.' + ext);
}
})
})
var upload = upload.array('fileup', 10);
The code responsible to upload the file and the content
router.post('/uploadfileandcontent',function(req,res,next){
upload(req,res,function(err) {
if(err) {
} else {
saveRecordsToDB(req, function(err,data){
if (err) {
res.redirect('/errorpage');
} else {
res. redirect('product/item');
}
});
}
});
});
Function that saves records to DB and makes the callback
function saveRecordsToDB (req, callback){
var args = {
data: {
"name" : req.body.name, //
"age" : req.body.age
},
headers: { "Content-Type": "application/json" }
};
// registering remote methods
client.registerMethod("postMethod", "http://url/uploadfileandcontent", "POST");
var req =client.methods.postMethod(args, function (data, response) {
callback(null, 'success?');
});
req.on('error', function (err) {
console.log('error');
});
}
Note: I also made use of NODE REST CLIENT to send http request.
This should work. Tell me if it doesn't.
router.post('/uploadfileandcontent', function(req,res,next){
upload(req,res,function(err) {
if(err) {
res.send('Error while uploading.');
}
saveRecordsToDB(req, function(err,data){
if (err) {
console.log(err);
req.flash('error', { msg: 'Error while saving data.' }); // Flash message -> need to configure your template to show it
}
// Saved to DB
req.flash('success', { msg: 'Saved' });
res.redirect('/product/item'); // go to this page
});
});
});
UPDATE
You will need to include const flash = require('express-flash'); to use flash message. Then you can load it to your app like this: app.use(flash());. The app is express loaded like this: const app = express();.
In your HTML you will access it in an array. Example using Jade:
//success
if messages.success
for success in messages.success
div #{success.msg} // Saved
//Error
if messages.errors
for error in messages.errors
div #{error.msg} // Error while saving data.

Cannot retrieve body text along with upload, Express js

I have a form that asks for a text and a file. I use multer for the file upload. The problem is I cannot retrieve the text with req.body if i use enctype=multipart/form-data
Route file
router.post('/new-job', function(req,res,next){
upload(req,res,function(err) {
if(err) {
return res.end("Error uploading file.");
}
});
var newJob = {
job_name: req.body.job_name, //Cannot retrieve this two
job_desc: req.body.job_desc,
};
var newJobData = new Jobs(newJob);
newJobData.save(function(err,user){
if(err)
console.log(err);
});
res.render('jobs/new-job', {job_added:true});
});
Multer configs
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, 'public/uploads');
},
filename: function (req, file, callback) {
callback(null, file.originalname);
}
});
Notes
I used method post
If i log the req.body.job_name it returns an undefined
If i remove the enctype=multipart/form-data i can retrieve the text just fine, though i cannot upload the file
You cannot access req.body contents until you're parsed the request, so either move your code inside your upload() callback, or get rid of the explicit upload() call entirely and just put upload before your route handler:
router.post('/new-job', upload, function(req, res, next) {
var newJob = {
// ...

Post file from one server to another,using node.js , needle , busboy/multer

I would like to move a small image from one server to another (both running node). As I search, I haven't found enough. This post remains unanswered.
As I started experimenting I wrote the following to the first server :
app.post("/move_img", function(req, res) {
console.log("post handled");
fs.readFile(__dirname + "/img_to_move.jpg", function(err, data) {
if (err) throw err;
console.log(data);
needle.post(server2 + "/post_img", {
data: data,
name : "test.jpg"
}, function(result) {
console.log(result);
res.send("ok");
});
});
});
This part seems to be working as I could be writing the data in the same server (using fs.writeFile) recreate the img.
Now as I am trying to handle the post in the other server I have a problem.
Server2:
app.post('/post_img', [ multer({ dest: './uploads/images'}), function(req, res) {
console.log("body ",req.body) // form fields
console.log("files ",req.files) // form files
res.send("got it");
}]);
This way i get an empty object in the files and the following in the body: { 'headers[Content-Type]': 'application/x-www-form-urlencoded', 'headers[Content-Length]': '45009' }
I think I could use busboy as an alternative but I can't make it to work. Any advice, tutorial would be welcome.
I solved my problem by using the following code,
server1 (using needle) :
app.post("/move_img", function(req, res) {
console.log("post handled")
var data = {
image:{
file: __dirname + "/img_to_move.jpg",
content_type: "image/jpeg"}
}
needle.post(server2 + "/post_img", data, {
multipart: true
}, function(err,result) {
console.log("result", result.body);
});
})
Server 2:
app.use('/post_img',multer({
dest: '.uploads/images',
rename: function(fieldname, filename) {
return filename;
},
onFileUploadStart: function(file) {
console.log(file.originalname + ' is starting ...')
},
onFileUploadComplete: function(file) {
console.log(file.fieldname + ' uploaded to ' + file.path)
}
}));
app.post('/post_img', function(req, res) {
console.log(req.files);
res.send("File uploaded.");
});
An alternative for the server 1 is the following (using form-data module):
var form = new FormData();
form.append('name', 'imgTest.jpg');
form.append('my_file', fs.createReadStream(__dirname + "/img_to_move.jpg"));
form.submit(frontend + "/post_img", function(err, result) {
// res – response object (http.IncomingMessage) //
console.log(result);
});
I'd simply read your file from the first server with the function readFile() and then write it to the other server with the function writeFile().
Here you can see use of both functions in one of my servers.
'use strict';
const express = require('express');
const multer= require('multer');
const concat = require('concat-stream');
const request = require('request');
const router = express.Router();
function HttpRelay (opts) {}
HttpRelay.prototype._handleFile = function _handleFile (req, file, cb) {
file.stream.pipe(concat({ encoding: 'buffer' }, function (data) {
const r = request.post('/Endpoint you want to upload file', function (err, resp, body) {
if (err) return cb(err);
req.relayresponse=body;
cb(null, {});
});
const form = r.form();
form.append('uploaded_file', data, {
filename: file.originalname,
contentType: file.mimetype
});
}))
};
HttpRelay.prototype._removeFile = function _removeFile (req, file, cb) {
console.log('hello');
cb(null);
};
const relayUpload = multer({ storage: new HttpRelay() }).any();
router.post('/uploadMsgFile', function(req, res) {
relayUpload(req, res, function(err) {
res.send(req.relayresponse);
});
});
module.exports = router;
see multer does all the tricks for you.
you just have to make sure you use no middle-ware but multer to upload files in your node starting point.
Hope it does the tricks for you also.

GridFS piping to Express response issue

I'm developing a web application where I store uploaded images inside MongoDB's GridFS. I have a problem trying to pipe the readable stream to the response, as it works sometimes but not every time. All images is stored inside GridFS and none of the files are corrupt as I'm able to extract the file with mongofiles and view it and the image looks exactly like the uploaded one.
Piping to the response works for some images, but some don't and I am pulling my hair off about this - I can't pinpoint the issue.
I am using gridfs-stream (1.1.0) with ExpressJS (4.0.0) and here's the response route:
exports.show = function (req, res, next) {
var id = req.params.id;
GridFS.exist({ _id: id }, function (err, exist) {
if (err) return handleError(err);
if (!exist) return res.send(404);
try {
var readStream = GridFS.createReadStream({ _id: gridId }).pipe(res);
} catch (err) {
return res.send(500, err);
}
});
};
And here's the upload route:
exports.create = function (req, res, next) {
var mime = req.files.file.mimetype;
var image = req.files.file.path;
var filename = req.files.file.originalname;
var writeStream = GridFS.createWriteStream({
filename: filename,
mode: 'w',
content_type: mime
});
writeStream.on('close', function (file) {
console.log(file);
return res.json(200, { status: 'success', url: '/api/images/' + file._id });
});
fs.createReadStream(image).pipe(writeStream);
};
Now as I mentioned, this works for some images, but not every image. I'm using Node 0.12.0 and MongoDB 2.6.8
Tell me if you need any additional information and I'll try to provide it.

Resources