Can't parse form-data twice - node.js

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'

Related

Saving Images React To Nodejs

I am trying to upload an image from my front end to the backend but it it doesn't send the image in the request
It says that the formdata is empty and it says that there's no image found, where is the problem and how can I fix this error?
Here is the code from the Frontend made in react:
const [userInfo, setuserInfo] = useState({
file:[],
filepreview:null,
});
const handleInputChange = (event) => {
setuserInfo({
...userInfo,
file:event.target.files[0],
filepreview:URL.createObjectURL(event.target.files[0]),
});
}
const [isSucces, setSuccess] = useState(null);
const submit = async () =>{
const formdata = new FormData();
formdata.append('avatar', userInfo.file);
console.log(formdata)
Axios.post("http://localhost:4000/imageupload", formdata,{
headers: { "Content-Type": "multipart/form-data" }
})
.then(res => { // then print response status
console.warn(res);
if(res.data.success === 1){
setSuccess("Image upload successfully");
}
})
}
The code of the Backend made in NodeJS:
const storage = multer.diskStorage({
destination: path.join(__dirname, './temp', 'uploads'),
filename: function (req, file, cb) {
// null as first argument means no error
cb(null, Date.now() + '-' + file.originalname )
}
})
app.post('/imageupload', async (req, res) => {
try {
// 'avatar' is the name of our file input field in the HTML form
let upload = multer({ storage: storage}).single('avatar');
upload(req, res, function(err) {
// req.file contains information of uploaded file
// req.body contains information of text fields
if (!req.file) {
return res.send('Please select an image to upload');
}
else if (err instanceof multer.MulterError) {
return res.send(err);
}
else if (err) {
return res.send(err);
}
const classifiedsadd = {
image: req.file.filename
};
res.send("ok")
});
}catch (err) {console.log(err)}
})
Edit:
Multer is essentially a nodejs router,i.e. a function that can be pipelined between your HTTP request and HTTP response.
I think that you should first make multer analyze your HTTP content and to actually populate the req.file before actually evaluate express parsers do their job.
const storage = multer.diskStorage({
destination: path.join(__dirname, './temp', 'uploads'),
filename: function (req, file, cb) {
// null as first argument means no error
cb(null, Date.now() + '-' + file.originalname )
}
})
let upload = multer({ storage: storage});
app.post('/imageupload', upload.single('avatar'), async (req, res) => {
try {
// 'avatar' is the name of our file input field in the HTML form
// req.file contains information of uploaded file
// req.body contains information of text fields
if (!req.file) {
return res.send('Please select an image to upload');
}
else if (err instanceof multer.MulterError) {
return res.send(err);
}
else if (err) {
return res.send(err);
}
const classifiedsadd = {
image: req.file.filename
};
res.send("ok")
}catch (err) {console.log(err)}
})
I am assuming that your upload code is working. Have you tried to read the HTTP request from your browser to see that the image has been correctly attached to the request?
Because probably the issue lies in the fact that you are not actually parsing the image.
const file = new File(userInfo.file, "avatar.png", {
type: 'image/png' // choose the appropriate
});
const formdata = new FormData();
formdata.append('avatar', file);
console.log(formdata)

A super simple Multer question, nested file uploading

I'm trying to do an image upload with Multer and Express. Doing just an image upload is going fine and everything works, the problem is, I want to send more than just one photo. Let me explain. I got the most basic form ever, not worth sharing. Then when submitting the form with JUST an image, the axios request looks like this:
async onSubmit() {
const formData = new FormData();
formData.append('file', this.person.personData.file)
this.obj.file = formData
try {
await axios.post('/projects/new', this.obj.file);
this.message = 'Uploaded';
} catch (err) {
console.log(err);
this.message = 'Something went wrong'
}
},
The post route in Express to receive the image looks like this:
personRoutes.post('/new', upload.single('file'), (req, res) => {
console.log('BODY: ', req.body)
console.log('REQ.FILE: ', req.file)
const person = new Person({
personData: {
file: req.file.path
}
});
person.save()
.then(result => {
console.log('YES', result)
res.redirect('/projects')
})
.catch(err => {
console.log('KUT', err)
})
});
req.file is the upload.single('file') file. Req.body will hold the text fields, if there were any. Ez Pz, so far so good. Now, where things get a bit sketchy is, what if I wanted to upload more than just one photo? So my obj object would not only hold a file property but a few others aswell. Currently I am directly sending the formData file with
await axios.post('/projects/new', this.obj.file);
But if my obj contained more than just a file, I would have to to this:
await axios.post('/projects/new', this.obj);
But what in the world should my Express post route look like? Because req.file will now (as far as I know) forever be undefined because file is not defined inside req object. It is defined in req.body object. Accessing the file as req.obj.file won't do anything. Any help would be very much appreciated. I don't even know if it is possible. And if not, what other options do I have?
Thanks in advance!
upload.array('file') should work. any number of files will be received.
here is an example:
multer code:
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads')
},
filename: (req, file, cb) => {
cb(null, "image"+Date.now()+file.originalname);
}
});
const fileFilter = (req,file,cb)=>{
if(file.mimetype==="image/jpeg" || file.mimetype==="image/png"){
cb(null, true);
}else{
cb(new Error("File type is not acceptable"),false);
}
}
const uploadImages = multer({storage:storage,
limits:{
fileSize: 1024*1024*10
},
fileFilter:fileFilter}).array("shopImage");
app.post code:
app.post("/shop", function(req,res){
uploadImages(req,res,function(err){
if(err){
console.log(err);
res.status(400).json({message:err.message});
}else{
console.log(req.files);
console.log(req.body);
....
}
});
....
})

"media type unrecognized" when uploading an image to Twitter using npm twit

I am working on an express node app that posts to twitter when a user inputs an image into a form. I am saving the image locally before uploading, which works. After I encode the file to base64, I try to upload the base64-encoded file to Twitter using twit's media/upload feature. When I do this, I get an error saying "media type unrecognized."
Here is my code:
app.post('/tweet', function(req, res){
var time = new Date().getTime()
let image = req.files.image
var imgpath = './images/img' + time + '.jpg'
image.mv(imgpath, function(err) {
if (err){
return res.status(500).send(err);
}
});
var b64content = fs.readFileSync(imgpath, { encoding: 'base64' })
T.post('media/upload', {media: b64content}, function(err, data, res) {
if (err) console.log(err);
console.log(data);
T.post('statuses/update', {status: 'posted picture at: ' + time, media_ids: [data.media_id_string]}, function(err, params, res) {
if (err) console.log(err);
console.log(params);
});
});
return res.redirect('/')
})
Thank you!
Got it!. I needed to put the T.post code in the brackets of image.mv's function
use postMediaChunked function
var filePath = '/absolute/path/to/file.png'
T.postMediaChunked({ file_path: filePath }, function (err, data, response) {
console.log(data)
})

Can't upload image to cloudinary

can you please tell me, what i doing wrong, when try to upload image to cloudinary?
app.js
I don't need to store images on server, so i store it in memory.
var cloudinary = require('cloudinary');
cloudinary.config({
cloud_name: 'hidden',
api_key: 'hidden',
api_secret: 'hidden'
});
var multer = require('multer');
var storage = multer.memoryStorage()
var upload = multer({ storage: storage })
Site form (jade/pug)
form(action="/?_csrf="+csrfToken method="post" enctype='multipart/form-data')
input(type="file" name="avatar")
input(type="submit" value="upload")
App post
app.post('/', upload.single('avatar'), function(req, res, next){
console.log('Should be undefined:', req.file.path); //yes
console.log('Should be the buffer:', req.file.buffer); //yes
cloudinary.uploader.upload(req.file.path, function(result) { console.log(result) });
});
and i get error
{ error: { message: 'Missing required parameter - file', http_code: 400 } }
i find out how (just use Datauri):
var dUri = new Datauri();
dUri.format(path.extname('TEST').toString(), req.file.buffer);
cloudinary.uploader.upload(dUri.content, function (err, result) {
if (err) {
console.log(err);
} else {
console.log(result);
}
});
I wasnt able to upload directly from my form to server but i used a trick first i stored files on disk then try to upload my file.
i use heroku hosting it means my files will be delete after 30 min. it means i will not have any storage problem.
//#1 i collect data into storage ./image/filename
await file.mv('./image/' + filename, async (err) => {
if (err) {
console.log("server'/upload' : faild to upload error =>" + err)
res.send('Save files => error : ' + err)
}
else {
try {
const client = await pool.connect()
//await client.query(`INSERT INTO test_table(id, name) VALUES(${1},'${"test"}')`)
const result = await client.query(`INSERT into post(musicname,artistname,price, music, picture)
VALUES ('${textName}','${textArtist}','${textPrice}', '${musicname}','${filename}')`);
res.send("server'/upload' : inserting new Data is Done.")
console.log("server'/upload' : inserting new Data is Done.")
client.release();
} catch (err) {
console.error(err);
res.send("Error " + err);
}
}
})
await fileMusic.mv('./music/' + musicname, (err) => {
if (err) {
console.log(err)
res.send('save files => error')
}
})
//#2 uplaoding collected data into cloudinary
await cloudinary.v2.uploader.upload('./image/' + filename, {public_id: `${filename}`},
function(error, result){
result;
console.log(result.url, error)
});

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