0

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.'
    });
});
georgeawg
  • 48,608
  • 13
  • 72
  • 95
Saini Basu
  • 11
  • 2

2 Answers2

0

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.

georgeawg
  • 48,608
  • 13
  • 72
  • 95
  • I can't remove bodyParser as all other APIs in my backend are using bodyParser. But i found a solution. Will be posting my solution soon. I used "multer" library instead of "connect-multiparty" and while calling my nodejs API "/upload" i used fetch instead of $http or httpService as fetch automatically assigns the correct Content-Type header (which in this case is multipart/form-data) – Saini Basu May 17 '19 at 12:53
  • The $http service will automatically set the correct Content-Type header if you use it correctly. See [How to POST FormData Using the $http Service](https://stackoverflow.com/a/41754333/5535245). – georgeawg May 17 '19 at 13:20
0

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);
});
Saini Basu
  • 11
  • 2
  • The $http service will automatically set the correct Content-Type header if you use it correctly. See [How to POST FormData Using the $http Service](https://stackoverflow.com/a/41754333/5535245). – georgeawg May 17 '19 at 13:22
  • Keep in mind that the ES6 promises returned from the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) are not integrated with the AngularJS framework. Only operations which are applied in the AngularJS execution context will benefit from AngularJS data-binding, exception handling, property watching, etc. – georgeawg May 17 '19 at 13:25