How to read FormData from a request on a server-side? - javascript

I send a file from a client-side to the server-side:
const formData = new FormData();
formData.set("file", file, file.name);
let ip = location.host;
$.ajax({
processData: false,
contentType: false,
type: "POST",
url: http() + ip + "/fileUpload",
data: formData,
success: %callback%,
error: function (err) {
return false;
}
});
The server-side (Node.js) catches this request via Express.js:
app.post("/fileUpload", function (req, res) {…}
Now, I want to access the uploaded file on a server-side in debugger.
Since the file is wrapped with FormData, I try to use req.body.get("file") following the FormData.get() API, and expect to get the file in base64/blob, but instead I get:
Uncaught TypeError: req.body.get is not a function
How can I access an uploaded file, which is wrapped by FormData from a POST-request?
The file is 100% uploaded to the server-side, since multer is capable of serializing the request to the file.
P.S. I've checked already How to send FormData objects with Ajax-requests in jQuery?, but there the answer demonstrates just a way to send a request, not to proceed the request.

I can propose a sort of a workaround. You can access it with multer as described in the tutorial
https://www.npmjs.com/package/multer
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file is the `avatar` file
// req.body will hold the text fields, if there were any
})
if you prepare the formData object in the following manner:
let formData = new FormData();
formData.set("file",file, file.name);
you shall be able to fetch the file object on the server side with multer as follows:
const upload = multer({ storage: './../uploads/' }).single('file');
upload(req, res, function(err) {
console.log("The file: " + req.file);
console.log("The path: " + req.file.path);
});

Related

How to submit a multipart image - Error: Multipart: Boundary not found

I have a client side javascript sdk that submits an image to a server side node.js api that uses the multer library to parse the image.
However ive noticed if i set a header to be content-type multipart-formdata multer will throw an error saying
Error: Multipart: Boundary not found
async submitDocument(id, side, image) {
const url = this.API_URL + "/api/document";
let formData = new FormData();
formData.set("image", image, "front.jpg");
formData.set("side", side);
let headers = new Headers();
headers.set("content-type", "multipart/form-data");
headers.set("Authorization", "Bearer " + this.API_KEY);
const request = {
method: "POST",
body: formData,
headers: headers,
};
try {
const response = await fetch(url, request);
const data = await response.json();
return data;
} catch (err) {
throw err;
}
}
As the error message says, a multipart/form-data content-type requires a boundary parameter.
Don't set the Content-Type yourself. Allow the browser to generate it from the formData object.
npm module connect-multiparty may helpful to you. From server-side node application.
server.js
const multipart = require('connect-multiparty');
const multipartMiddleware = multipart();
router.post('/api/document', multipartMiddleware);
router.post('/api/document', (req, res) => {
console.log(req.files)
})
post-man api test sample -
https://i.stack.imgur.com/vxBpz.png

Sending form data in nodejs using https.request

I am trying to post a request with my nodejs server to another server and then I have to save response in a file. I am using nodejs https.request module.
This is my request:
var formData = new FormData();
formData.append('first',3);
formData.append('second', '25');
formData.append('source_file', fs.createReadStream(sourcefile));
formData.append('source_image', fs.createReadStream(sourceimage));
var options = {
hostname: 'ip',
path: '/api/path',
method: 'POST'
}
var file = fs.createWriteStream("file.pdf");
var req = https.request(options, (response) => {
response.pipe(file);
console.log("File saved");
response.send("done")
});
req.on('error', (e) => {
console.error(e);
});
req.write(formData);
req.end();
But I am getting the error
First argument must be a string or Buffer
I tried sending my files using formData.toString() but on using this, error disappears but My files are not working and also I have sent data like this:
var formData = new FormData();
formData = {
first: 3,
second: '25',
source_file: fs.createReadStream(sourcefile),
source_image: fs.createReadStream(sourceimage)
};
How can I send my files to other server using this request.
Thanks
I assume you are using form-data.
To fix the First argument must be a string or Buffer error replace:
req.write(formData);
req.end();
with
formData.pipe(req);
(formData behaves like a Node.js ReadableStream)
You should also add headers to your request:
var options = {
hostname: 'ip',
path: '/api/path',
method: 'POST',
headers: formData.getHeaders()
}
Source: https://github.com/form-data/form-data#alternative-submission-methods
I once faced an issue similar to this. I resolved it using the form-data package available on NPM here with the axios package here
the snippet below worked for me
const FormData = require("form-data");
const axios = require("axios");
const form = new FormData();
form.append("first", 3);
// other data should go here
form.append("file", fs.createReadStream("filePath"));
axios({
method: "post",
url: "url",
data: form,
headers: { ...form.getHeaders() }
});
You can use node inbuilt body-parser module to parse the form data into JSON and
you have to use
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true }));
And when you do req.body then it will your form data into an object form.

How to configure API endpoint to receive file from ember-uploader component

I'm trying to figure out how to use ember-uploader, I have the following component (like the one in the README)
export default EmberUploader.FileField.extend({
filesDidChange: function(files) {
const uploader = EmberUploader.Uploader.create({
url: (ENV.APP.API_HOST || '') + '/api/v1/images/',
});
console.log(uploader);
if (!Ember.isEmpty(files)) {
var photo = files[0];
console.log(photo);
uploader.upload(photo)
.then(data => {
// Handle success
console.log("Success uploading file");
console.log(data);
}, error => {
// Handle failure
console.log("ERROR uploading file");
console.log(error);
});
}
}
});
The express API endpoint is listening for a POST request.
var saveImage = (req, res, next) => {
let body = req.body;
res.json({
data: body
});
};
But the body is empty after the request is done. I really don't know how to implement the API endpoint in order to get the file, I tried to see the req object and it doesn't contains the file.
Debugging it, After select a file using the component I get the following info in the console.
Seems that the API endpoint works because I get the following output:
POST /api/v1/images/ 200 27.284 ms - 11
But I can't get the file.
SOLUTION
In Express 4, req.files is no longer available on the req object by
default. To access uploaded files on the req.files object, use a
multipart-handling middleware like busboy, multer, formidable,
multiparty, connect-multiparty, or pez.
Following this blog, the code below was added to the API and the ember-uploader code posted in the question worked as expected.
import formidable from 'formidable';
var saveImage = (req, res, next) => {
var form = new formidable.IncomingForm();
form.parse(req);
form.on('fileBegin', function (name, file){
file.path = __dirname + '/tmp/' + file.name;
});
form.on('file', function (name, file){
res.json({
data: file.name
});
});
};

How to send file in a request and download the file within the response without redirecting

I an trying to create a service which takes a xlsx template file and response a populated xlsx file with some values. What I have done so far is,
index.html
<input name="file" type="file" onchange="callthis()"/>
script.js
// callthis sends the file from client to server
function callthis() {
var formData = new FormData($(this).files[0]);
$.ajax({
url: '/uploadTemplate',
type: 'POST',
data: formData,
success: function (data) {
console.log(data);
alert(data)
},
cache: false,
contentType: false,
processData: false
});
}
serverRouter.js
router.post('/uploadTemplate', function(req, res, next){
let uploadedFilePath = null;
// I'm using multer for handling formdata in the server
var upload = multer({ dest: Locator.temp.temp });
//configure the multer
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, Locator.temp.temp);
},
filename: function (req, file, callback) {
uploadedFilePath = file.fieldname + '-' + Date.now() + '.xlsx';
callback(null, uploadedFilePath);
}
});
var upload = multer({ storage : storage}).single('file');
//in here i am uploading the file.
//and reading the file ugin XLSX modules.
//doing some changes to xlsx json object
//and write the data to a file in a temp folder
//i'm using res.download method to send downloadable file back to client
res.download(Path.join(Locator.temp.temp, uploadedFilePath));
});
})
Using above codes, i could upload the file and get response. success method prints out details i added with some unreadable characters. But i could not download the file.
How can i download the file. Are there any different and better approach for this situation.
You can't attach a download to an AJAX request. You will have to send the download URL in the AJAX response and then have your client side script open the URL
In the server:
let response = {downloadUrl: Path.join(Locator.temp.temp, uploadedFilePath)}
res.json(response)
In the client:
window.open(ajaxResponse.downloadUrl);

ngFileUpload and Multer - saving uploaded file to a folder

I'm (very) new to angular MEAN and I'm trying to upload a file (pdf, specifically) and save it to server. I know it's probably a stupid question, but I cannot find any example on the server on how to actually save the uploaded file to the server's storage
I'm using ng-file-upload directive from https://github.com/danialfarid/ng-file-upload, Express for server, and ofc, AngularJS for the file upload.
POST UPDATED!! See below
More info: I'm using Yeoman's full mean stack generator for this project
UPDATE:
I've tried using multer (https://github.com/expressjs/multer) to save the uploaded file to server. I got this error when trying to upload the file (it returns 500 error)
Error: Unexpected field
at makeError ({proj_folder}/node_modules/multer/lib/make-error.js:12:13)
at wrappedFileFilter ({proj_folder}/node_modules/multer/index.js:39:19)
at Busboy.<anonymous> ({proj_folder}/node_modules/multer/lib/make-middleware.js:112:7)
at emitMany (events.js:127:13)
at Busboy.emit (events.js:201:7)
at Busboy.emit ({proj_folder}/node_modules/busboy/lib/main.js:31:35)
at PartStream.<anonymous> ({proj_folder}/node_modules/busboy/lib/types/multipart.js:213:13)
at emitOne (events.js:96:13)
at PartStream.emit (events.js:188:7)
at HeaderParser.<anonymous> ({proj_folder}/node_modules/dicer/lib/Dicer.js:51:16)
at emitOne (events.js:96:13)
at HeaderParser.emit (events.js:188:7)
at HeaderParser._finish ({proj_folder}/node_modules/dicer/lib/HeaderParser.js:68:8)
at SBMH.<anonymous> ({proj_folder}/node_modules/dicer/lib/HeaderParser.js:40:12)
at emitMany (events.js:127:13)
at SBMH.emit (events.js:201:7)
updated HTML
<form accept-charset="UTF-8" class="form" name="form" ng-submit="$ctrl.submitForm(form)"
enctype="multipart/form-data">
...
<input ngf-select ng-model="$ctrl.paperFile" ngf-model-options="{allowInvalid: true}" name="paper" ngf-accept="'application/pdf'" required="" type="file" >
...
</form>
submitForm method
...
this.Upload.upload({
url:'/paperUpload',
method: 'POST',
file: this.paperFile,
fields:{
_id:this.user._id
}
})
.then(function(resp){
console.log('Success upload');
console.log(resp.data);
}, function(error){
console.log('fail upload');
console.log(error);
}, function(evt){
console.log('upload on progress');
console.log(evt);
});
Server route:
var express = require('express');
var multer = require('multer');
var router = express.Router();
var upload = multer({dest:'uploads/',
rename: function(fieldname, filename){
return filename+"_"+Date.now();
}});
router.post('/paperUpload', upload.single('paper'), uploadPaper);
...
//method to upload
export function uploadPaper(req,res){
res.status(204).end();
}
The folder 'uploads' is created, but the file is not uploaded and always returned fail
Any help is appreciated,
Thank you
Do these steps
npm install ng-file-upload
include ng-file-upload.min.js in your angular index .html
Use this example to copy form to your angular page from where u want to upload file. -- http://jsfiddle.net/0m29o9k7/
Copy this code outside of any form which is already there:
Change this url from example code to where you want to upload files -- url: 'https://angular-file-upload-cors-srv.appspot.com/upload',
In your server.js or app.js which ever you are using as (node server.js) to start app add these lines
var crypto = require('crypto');
var mime = require('mime');
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'app/app-content/images/')
},
filename: function (req, file, cb) {
crypto.pseudoRandomBytes(16, function (err, raw) {
cb(null, raw.toString('hex') + Date.now() + '.' + mime.extension(file.mimetype));
});
}
});
var upload = multer({ storage: storage });
// make '/app' default route
app.post('/', upload.any(), function (req, res) {
res.send(req.files);
});
Change 'app/app-content/images/' this where you want your uploaded file will be
This code points your file upload url to index of your node server.
then you will be able to see the uploaded file.
Try this, I have never seen the 'file' or 'fields' options of Upload.upload. Do you know those are working? I just overcame a similar error by adding the arrayField to my POST call.
if you get the same error try removing 'fields' and adding a new key to the data object with the _id you wish to pass along.
this.Upload.upload({
url:'/paperUpload',
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data ; boundary = ----WebKitFormBoundaryvlb7BC9EAvfLB2q5'
},
arrayKey: '',
data: {
paper: this.paperFile,
},
fields:{
_id:this.user._id
}
})
.then(function(resp){
console.log('Success upload');
console.log(resp.data);
}, function(error){
console.log('fail upload');
console.log(error);
}, function(evt){
console.log('upload on progress');
console.log(evt);
});

Categories