Multer incorrectly parses formData - node.js

Multer receives the Form Data, but leaves all fields, including the image files, in the req.body object. Here is my code:
React:
const state = {
// other fields
images: [], // array of image files
};
let formData = new FormData();
// append other fields
formData.append("images", state.images);
await fetch(url, {
body: formData,
// config
});
Express:
const express = require("express");
const router = express.Router();
const controller = require("./controller");
const multer = require("multer");
const storage = multer.memoryStorage();
const imageFilter = (req, file, cb) => {
// accept image files only
if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/i)) {
return cb(new Error("Only image files are allowed!"), false);
}
cb(null, true);
};
const upload = multer({ storage, fileFilter: imageFilter });
// other routes
router.post("/", upload.array("images"), controller.handleImagePost);

Multer doesn't parse the Form Data files if they are nested in an array. It's best to loop over your React state array, and append each file individually to the formData object. (See FormData API and Multer docs)
for (const image of state.images) {
formData.append("image", image, image.path);
}
Make sure to match the form data field name in your multer middleware code
router.post("/", upload.array("image"), controller.handleImagePost);

Related

Retrieivng image from DB using multer

I am working on MERN application and I am facing issue in displaying the image.Using multer, the image path store in the MongoDB after file uploaded successfully and the image also stores in the folder "uploads", but there is problem I am getting while retrieving the image path from db.
all the text data retrieved but displaying image give me error.
Error I got:
CANNOT GET http://localhost:3000/uploads/image-1614468761737.jpg
Here is the code.
const express = require("express")
const path = require("path")
const route = express.Router()
const Post = require("../models/postModel")
const multer = require("multer")
const storage = multer.diskStorage({
destination(req,file,cb){
cb(null,"uploads/")
},
filename(req,file,cb){
cb(null, `${file.fieldname}-${Date.now()}${path.extname(file.originalname)}`)
}
})
const upload = multer({
storage,
filefilter: function(req,file,cb) {
const filetypes = /jpg|jpeg|png/
const extname = filetypes.test(path.extname(file.originalname).toLowerCase())
const mimetype = filetypes.test(file.mimetype)
if(extname && mimetype){
return cb(null, true)
}else{
cb(null,false)
}
},
})
route.post("/upload",upload.single("image"),(req,res)=>{
const file = req.file.path.replace(/\\/g,"/" )
res.send(`/${file}`)
})
route.post("/", async(req,res)=>{
const post = req.body
try {
const createpost = new Post(post)
await createpost.save()
res.status(200).json(createpost)
} catch (error) {
res.status(404).json({msg:"create post failed"})
}
})
module.exports = route
in the main file I also add
app.use("/uploads",express.static(path.join(__dirname,"/uploads")))
file structure:
file structure and uploads folder is in the root
GitHub:
https://github.com/mozi47/Check-error

Body-parser not working with POST-MAN form data

I try to send image, some text in form data and I try to console.log(req.body) It's always return {} I've read many topic about this
here is my route/index.js
const express = require('express');
const router = express.Router();
const bodyParser = require('body-parser');
router.use(bodyParser.urlencoded({extended:true}));
router.use(bodyParser.json());
router.route('/').post(AdminController.list);
I tryo to add urlencoded but it still not working .
bodyParser cannot handle multipart/form-data
Try Multer, From official docs:
Multer is a node.js middleware for handling multipart/form-data, which
is primarily used for uploading files. It is written on top of busboy
for maximum efficiency
Multer adds a body object and a file or files object to the request
object. The body object contains the values of the text fields of the
form, the file or files object contains the files uploaded via the
form.
See a working example:
const Multer = require('multer');
const multer = Multer({
storage: Multer.memoryStorage(),
limits: {
fileSize: 5 * 1024 * 1024 // no larger than 5mb, you can change as needed.
}
});
app.post('/upload', multer.single('file'), (req, res) => {
// req.body will contain the text fields, if there were any
fs.createWriteStream('./uploads/' + req.file.originalname)
var fileWriteStream = fs.createWriteStream(req.file.originalname);
fileWriteStream.on('finish', () => {
console.log('file saved successfully');
res.send({ message: 'file saved successfully' })
})
fileWriteStream.end(req.file.buffer)
})

how to read posted data on node js api

i want to read the csv data uploaded to backened.
for this i am sending the data via post from front end..
frontend code:
fileEvent(e) {
this.filedata = e.target.files;
if (this.filedata.length > 0) {
const file: File = this.filedata[0];
console.log(file);
const formData: FormData = new FormData();
formData.append('files', file, file.name);
this.http.post('myUrl', {file: formData}, this.options)
.subscribe((res) => {
});
}
}
screenshot of my file:
now on backened i have written route on api.js that directs me
to the controller i have created.
my api.js code:
router.post('/product/csvdata', function (req, res) {
productimport.importcsvProduct(req, res);
});
and finally on my controller i am consoling my data:
var product = {
importcsvProduct: function (req,res) {
console.log(req.body.file);
}
};
module.exports = product;
but i am getting empty {} in console..??
can anyone check whats wrong with this..??
You need to use a file handling middleware in this case, such as multer.
const express = require('express')
const multer = require('multer')
const upload = multer({ dest: 'uploads/' })
const app = express()
app.post('/profile', upload.single('csvdata'), function (req, res, next) {
// req.file is the `csvdata` file
// req.body will hold the text fields, if there were any
})

Can't upload file using express-fileupload

I'm using express-fileupload module to parse uploaded file.
Upload is done with axios.
const formData = new FormData();
formData.append("file", data.gameCover);
formData.append("gameTitle", data.gameTitle);
formData.append("gamePrice", data.gamePrice);
formData.append("description", data.description);
return axios.post(apiUrl + "/games/add", formData).then(res => {
dispatch({ type: ADD_GAME, payload: res.data.game });
});
This is the POST request
Serverside code looks like this:
router.use(fileUpload());
router.post("/add", (req, res) => {
if (!req.files) return res.status(400).send("No files were uploaded.");
Of course I'm getting "No files were uploaded" when trying to upload.
Finally after debugging step after step found that data.gameCover is an array
so that's the solution
formData.append("file", data.gameCover[0]);
You can optionaly use multer for handling multipart/formdata.
you can then get the uploaded file as follows
const express = require('express');
const path = require('path');
const router = express.Router();
const multer = require('multer');
const storage = multer.diskStorage(
{destination: (req, file, cb)=>{
cb(null, path.join(__dirname, '../uploads'));
},
filename: (req, file, cb)=>{
cb(null, file.originalname);
}
});
let upload = multer({storage: storage});
// access the uploaded file with your route handler
router.post('/upload',upload.single('file'), (req, res, next)=> {
if(req.file){
//you can access your uploaded file
}
});

Sending file from one node js server to another

So on first server I have route like this:
const express = require('express');
const router = express.Router();
const FormData = require('form-data');
const fetch = require('node-fetch');
const multer = require('multer');
const storage = multer.memoryStorage();
const upload = multer({ storage });
router.post('/', upload.single('file'), async (req, res) => {
const form = new FormData();
form.append('folderId', req.body.folderId);
form.append('file', req.file.buffer, req.file.filename);
const result = await fetch('http://localhost:3003/users', { method: 'POST', body: form }).then(res => res.json());
res.json(result);
})
On this server, it works fine, I can see req.file and it's buffer. So I wanna send this file (without storing it on first server, it exists only in memory and as buffer) to another.
Other server route is like this:
const express = require('express');
const router = express.Router();
const multer = require('multer');
const path = require('path');
const putanja = path.join(__dirname, '../uploads/users');
const storage = multer.diskStorage({
destination: (req, file, cb) => {
console.log('entered here?')
if (!req.body.folderId) return cb({ message: 'no folderId' });
if (!fs.existsSync(putanja + '/' + folderId)) fs.mkdirSync(putanja + '/' + folderId);
cb(null, putanja + '/' + folderId);
},
filename: (req, file, cb) => cb(null, file.originalname)
});
const upload = multer({ storage });
const fs = require('fs');
router.post('/', upload.single('file'), async (req, res) => {
console.log(req.body)
console.log(req.file)
res.json({ status: 'ok' })
})
So on second server, it doesn't even enter the multer middleware, req.file is always defined, and that console.log('entered here?') is never seen. Looks like I'm not passing data as multipart-form?
Also, second server, when sending file directly to it via postman, works.
So my question, how do I send that file? As a buffer? Stream? Base64? I think I tried everything, even changed node-fetch to request, but still no luck.
So on second server, it doesn't even enter the multer middleware, req.file is always defined, and that console.log('entered here?') is never seen. Looks like I'm not passing data as multipart-form?
So this mean your second server doesn't understand the Content-Type of request.
So do one thing add Content-Type parameter in header when you are sending request to second server
Add Content-Type to multipart/form-data
or if you don't know pass headers : {
'Content-Type' : undefined
} http will set header for you
You send your request to /users (http://localhost:3003/users) yet your second server expects the request on /.
Try changing either one to match the other.
'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) {
console.log('hell0 proto');
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;

Resources