Multiparty file upload issue with body parser using angularjs and nodejs [duplicate] - node.js

This question already has an answer here:
AngularJS Upload Multiple Files with FormData API
(1 answer)
Closed 3 years ago.
Trying to upload a file from Angularjs UI to nodejs server but facing issues with bodyparser, adding limit to it throws -
"SyntaxError: Unexpected token - in JSON at position 0",
if limit not added throws -
"Payload too large"
I am using connect-multiparty middleware to upload the file. Tried with {limit: '50mb'} in bodyparser and without any limit as well.
UI Code -
$('#imgupload').on('change', function (evt) {
let uploadedFiles = evt.target.files;
let formData = new FormData();
for (var i = 0; i < uploadedFiles.length; i++) {
formData.append("uploads[]", uploadedFiles[i],
uploadedFiles[i].name);
}
let url = "/upload";
httpService.restApi(url,formData)
.then(function (response) {
console.log("the file has been uploaded to local server
",response);
});
});
Nodejs (server code)-
const multipart = require('connect-multiparty');
const multipartMiddleware = multipart({ uploadDir: './uploads' });
app.use(bodyParser.json({limit: '50mb'}));
app.use(bodyParser.urlencoded({extended: true}));
app.post('/upload', multipartMiddleware, (req, res) => {
res.json({
'message': 'File uploaded succesfully.'
});
});

Remove the bodyParser middleware from the path:
const multipart = require('connect-multiparty');
const multipartMiddleware = multipart({ uploadDir: './uploads' });
̶a̶p̶p̶.̶u̶s̶e̶(̶b̶o̶d̶y̶P̶a̶r̶s̶e̶r̶.̶j̶s̶o̶n̶(̶{̶l̶i̶m̶i̶t̶:̶ ̶'̶5̶0̶m̶b̶'̶}̶)̶)̶;̶
̶a̶p̶p̶.̶u̶s̶e̶(̶b̶o̶d̶y̶P̶a̶r̶s̶e̶r̶.̶u̶r̶l̶e̶n̶c̶o̶d̶e̶d̶(̶{̶e̶x̶t̶e̶n̶d̶e̶d̶:̶ ̶t̶r̶u̶e̶}̶)̶)̶;̶
app.post('/upload', multipartMiddleware, (req, res) => {
res.json({
'message': 'File uploaded succesfully.'
});
});
The contents is application/form-data, not application/json or application/x-www-form-urlencoded.

If you use multer and make the API call using $http explicitly setting the "Content-Type" header to multipart/form-data you will get "Multer: Boundary not found error" and if you remove the "Content-Type" header or set it to false it throws - "Converting circular structure to JSON error". Hence i used "fetch" to make the API call as it automatically identified the "Content-Type".
UI Code (modified as below) -
$('#imgupload').unbind('change').on('change', function (evt) {
evt.stopPropagation();
evt.preventDefault();
let uploadedFiles = evt.target.files;
let formData = new FormData();
for(let i=0; i<uploadedFiles.length;i++){
formData.append("uploads", uploadedFiles[i], uploadedFiles[i].name);
}
let url = '/upload';
var req = {
method: 'POST',
body: formData
}
fetch(url,req).then(function(response) {
console.log("the file has been uploaded to local server ",response);
$scope.uploadToSftp();
});
});
Nodejs Code (modified as below) -
const multer = require('multer');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads/')
},
filename: function (req, file, cb) {
cb(null, file.originalname)
}
})
const multipartMiddleware = multer({ storage: storage });
app.use(bodyParser.json({limit: '50mb'}));
app.use(bodyParser.urlencoded({
extended: true
}));
app.post('/upload', multipartMiddleware.array("uploads",2), function(req, res)
{
console.log("the upload api is called");
return res.send(req.files);
});

Related

When uploading a file in POST, req.body is {} in Node js [duplicate]

This question already has answers here:
Node/Express file upload
(11 answers)
Closed 8 months ago.
React code - FileUploader.js
// React - FileUplader.js
const handleSubmission = (e) => {
e.preventDefault();
if(isSelected === false){
alert("load the file");
}
else{
const formData = new FormData();
formData.append("certificate",selectFile);
// API CALL
fetch("http://localhost:8080/upload", {
method: "POST",
body: formData,
headers : {
"Content-Type" : "multipart/form-data"
}
}).then((response) =>response.json())
.then((result)=>{
console.log("Success : ", result);
})
.catch((error)=>{
console.error("Error : ",error);
});
}
};
Nodejs code - Server.js
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended : true}));
app.post('/upload', async function(req ,res){
try {
const file = req.files; // undeifined
const bodyData = req.body; // {}
console.log("file : ",file);
console.log("bodyData : ",bodyData);
res.status(200).send({
message: "FILE RECEIVED!"
});
} catch(error){
res.send("ERROR")};
});
Problem
Why req.body is {} in node js
I tried using MULTER but got the same result
MDN says that FormData object is not a simple object, but a special object created for XMLHttpRequest transmission and cannot be recorded with the console.
Your front end code is correct. You did not set up multer. Multer is actually a middleware, will be listening to multipart/form-data. [check the docs][1]
Multer is a node.js middleware for handling multipart/form-data, which
is primarily used for uploading files.
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.
to handle files on node.js environment, write a middleware:
const multer = require("multer");
const { randomBytes } = require("crypto");
const fileStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "images");
},
filename: (req, file, cb) => {
cb(null, randomBytes(4).toString("hex") + "-" + file.originalname);
},
});
const fileFilter = (req, file, cb) => {
if (
file.mimetype === "image/png" ||
file.mimetype === "image/jpg" ||
file.mimetype === "image/jpeg"
) {
cb(null, true);
} else {
cb(null, false);
}
};
module.exports = multer({ storage: fileStorage, fileFilter }).single("image"); //image is the field name
Then use it in express app
const multer = require("./middlewares/multer");
app.use(cors());
app.use(bodyParser.json());
app.use(multer);
app.use(bodyParser.urlencoded({extended : true}));
[1]: http://expressjs.com/en/resources/middleware/multer.html#:~:text=Multer%20is%20a%20node.,multipart%2Fform%2Ddata%20).

Multer react + node js unable to get req.file

Hi I am trying to upload a file from fronend to backend using multer
Front End
var formData = new FormData();
formData.append("files", image[0]);
formData.append("data", JSON.stringify({status: 'ACK', message: "You are fu*ked"});
return http.axios
.post(apiUrl + apiDomain + "/createAnnouncement", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
})
.then((res) => res);
Backend
const bodyParser = require("body-parser");
const Express = require("express");
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, config.get("announcemnt_upload_file_storage"));
},
filename: function (req, file, cb) {
cb(null, file.filename + "_" + Date.now());
},
});
var upload = multer({ storage: storage });
const Router = Express.Router();
Router.route("/createAnnouncement").post(
upload.single("files"),
(req , resp, next) => {
console.log(" >>>>>>>", req.file);//THis returns undefined
console.log(">>>>", req.files);//This returns undefined
resp.send("Siccess")
}
);
Below is my Req snapshot
Its not getting uploaded to storage and its returning undefined when called req.file
But if I try to see req.body I could see [Object File] in console
PLease suggest where I am going wrong
I think this may help https://github.com/RUSHI-GADHIYA/uploading-and-updating-image see this

How to Upload File from angular7 to Node.js server

My node.js code is working 100% by Postman,
but in angular when I send a FormData and nothing happened in server, no error but the file not uploaded.
how can i upload file by angular?
HTML Compnent:
<form>
<input type="file" (change)="OnFileSelected($event)" name='photo'>
<button type='submit' (click)="OnUpload()">Save Post</button>
</form>
Ts Compnent:
OnFileSelected(event){
this.SelectedFile = event.target.files[0] as File;
}
OnUpload(){
const form: FormData = new FormData();
form.append('photo', this.SelectedFile, this.SelectedFile.name);
//Convert to Json because 'Unexpected token - in JSON at position 0 at JSON.parse' error in server
let responseBody: {} = JSON.stringify(form);
this.http.post(URL, responseBody).subscribe(event => { console.log(event)}, err => {console.log(err)
});
}
Node.js Server:
const path = require('path');
const express = require('express');
const multer = require('multer');
const bodyParser = require('body-parser')
const router = express.Router();
const DIR = './uploads';
let storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, DIR);
},
filename: (req, file, cb) => {
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
let upload = multer({ storage: storage });
router.use(bodyParser.json());
router.use(bodyParser.urlencoded({ extended: true }));
router.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200');
res.setHeader('Access-Control-Allow-Methods', 'POST');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
router.post('/upload-image', upload.single('photo'), async function (req, res) {
console.log(req.body);
if (!req.file) {
console.log("No file received");
return res.send({
success: false
});
} else {
console.log('file: ',req.file);
return res.send({
success: true
})
}
});
You need to specify that your Request is a form-data request:
// Create Form Data
const formData: FormData = new FormData();
formData.append('photo', this.SelectedFile, this.SelectedFile.name);
// Create options for the request
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'multipart/form-data', // <-- IMPORTANT
'Accept': 'application/json'
})
};
this.http.post(URL, formData, httpOptions).subscribe(...)
There are many ways to transfer file to the server, if it's a common scenario, then I will suggest using Dropzone.js angular wrapper.
Better have a custom angular component with all the custom configuration of Dropzone to meet your needs.
Using it is also quite easy, once you have installed the package, file input is as simple as follow:
<dropzone [config]="config" [message]="'Click or drag images here to upload'"
(error)="onUploadError($event)" (success)="onUploadSuccess($event)"></dropzone>
Documentation can be found here:
https://www.npmjs.com/package/ngx-dropzone-wrapper
You need to first instantiate your file in OnInit() before creating an instance in your OnUpload() function which you have done:
ngOnInit() {
this.form = new FormGroup({
photo: new FormControl(null, {
validators: [Validators.required]}) }
You can remove the validators if you like, you can also edit your onFileSelected() function like this:
this.SelectedFile = event.target.files[0] as File;
this.form.patchValue({ photo: file });
this.form.get('photo').updateValueAndValidity();
const reader = new FileReader();
reader.readAsDataURL(file);
console.log(file);
call your function like this:
onUploadFile(event: Event){}

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;

How to get FormData in Express js?

I'm trying to upload a file to my express server. The client code looks like this:
axios.post('localhost:3030/upload/audio/', formData)
And in my express server:
App.use(bodyParser.urlencoded({ extended: true }));
App.use(bodyParser.json());
App.post('/upload/audio/', function uploadAudio(req, res) {
let quality = ['320', '128'];
let file = req.body;
console.log(file)
res.send('Frick')
}
However, even though the mp3 file is sent:
The req.body is empty when logged (note the empty object):
How can I get the formData (and file) in Express.js?
As #Tomalak said body-parser does not handle multipart bodies.
So you need to use some third party module I suggest use awesome module multer
I tried to do your code, hope it can help you
App.post('/upload/audio/', function uploadAudio(req, res) {
var storage = multer.diskStorage({
destination: tmpUploadsPath
});
var upload = multer({
storage: storage
}).any();
upload(req, res, function(err) {
if (err) {
console.log(err);
return res.end('Error');
} else {
console.log(req.body);
req.files.forEach(function(item) {
console.log(item);
// move your file to destination
});
res.end('File uploaded');
}
});
});

Resources