Sending form data in nodejs using https.request - javascript

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.

Related

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

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);
});

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

post $http request using file type input and get req.body and req.file not using multer nodejs

my tried code is :
//jade
input(type='file', ng-model='filename',file-model='Image', required='')
// controller.js
$scope.reupload = () => {
$scope.user = {
UserName: 'sam',
FirstName: 'sameer',
};
const fd = new FormData();
$scope.theData = {};
fd.append('file', $scope.Image);
$scope.theData.i = fd;
$http({
method: 'POST',
url: '/api/uploadresume',
data: $scope.theData,
})
.then((data) => {
console.log(data);
}).catch((err) => {
console.log(`error ${err}`);
});
};
//server.js
app.post('/api/uploadresume', api.UploadAlumniResume);
//api.js
exports.UploadAlumniResume = (req, res) => {
console.log('req.body', req.body);
console.log('req.file', req.file);
};
i am getting file data inito $scope.Image,
and i append the data using of const fd = new FormData().
fd as append the $scope.Image.
then store the $scope.theData data to the post request.
i am getting result is:
// req.body $ req.file consoles
req.body { i: {} }
req.file undefined
I need to access the req.body data and read and fs write the req.file data .
please give any solution to me !
You can't put a FormData inside an object that you're posting. It has to be the data itself.
const fd = new FormData();
fd.append('file', $scope.Image);
$http({
method: 'POST',
url: '/api/uploadresume',
data: fd,
processData: false
})
when you are image or file uploading , you need to pass header 'Content-Type': 'multipart/form-data'
if you are using bodyparser , then body parser is not able to handle form-data , it is only handle application/x-www-form-urlencoded and application/json data
as you getting req.file undefined this because bodyparser not work with form-data
so use multer to handle form-data.

Unexpected token - while parsing json request

I have two node servers and I am trying to send files between them using a rest api. However when I am sending the data I get a "Unexpected token -"on the receiving server. On the sender I get an [Error: write after end].
My router code:
var express = require('express');
var multer = require('multer');
var path = require('path');
var Router = express.Router;
const MODULES_PACKAGES_UPLOAD_DIR = path.resolve('/tmp');
module.exports = function() {
var router = new Router();
var storage = multer.diskStorage({
destination: function(req, file, cb){
cb(null, MODULES_PACKAGES_UPLOAD_DIR);
}
});
var upload = multer({storage: storage});
router.post('/fileUpload', upload.array(), function(req, res){
debug('We have a a file');
//Send the ok response
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
res.end('\n');
}
The sending code:
var Util = require('util');
var http = require('request-promise');
var request = require('request');
var fs = require('fs');
var Post = require('http');
var FormData = require('form-data');
//Generate the form data
var formdata = modules.map(function(fileName){
return fs.createReadStream('/opt/files/'+fileName);
});
var data = getData(); //Gets the body of the code as a promise
return Promise.all(data)
.then(function(dataResults){
var options = {
method: 'POST',
uri: 'https://' + name +'/file',
rejectUnauthorized: false,
timeout: 2000,
body: {
keys: keyResults,
modules: modules,
},
formData: { <====== If I remove this section everything works
'module-package': formdata,
},
json: true // Automatically stringifies the body to JSON
};
request.post(options, function(err, response){
if( err){
debug('Error: ',err);
}
else{
debug('We posted');
}
});
The weird thing is that if I remove the formData section then everything works but when it is there I get an exception that says:
SyntaxError: Unexpected token -
at parse (/home/.../projects/node_modules/body-parser/lib/types/json.js:83:15)
Does anyone have any idea what I could be doing wrong??
Just in case anyone in the future comes with the same problem. As #Bergi mentioned. You cant have both json data and form data. You need to choose either one. The solution is to just pass the json data as apart of the form like.
var options = {
method: 'POST',
uri: 'https://' + name +'/file',
rejectUnauthorized: false,
timeout: 2000,
body: {
},
formData: {
'module-package': formdata,
keys: keyResults,
modules: modules,
},
json: true // Automatically stringifies the body to JSON
};
request.post(options, function(err, response){
if( err){
debug('Error: ',err);
}
else{
debug('We posted');
}
});
In my case, the header of the HTTP Request contained "Content-Type" as "application/json".
So here are the things to check:
Send only either form-data or json body. NOT BOTH.
Check for Headers if the "Content-Type" is mentioned. Remove that.

Add parameters to HTTP POST request in Node.JS

I've known the way to send a simple HTTP request using Node.js as the following:
var http = require('http');
var options = {
host: 'example.com',
port: 80,
path: '/foo.html'
};
http.get(options, function(resp){
resp.on('data', function(chunk){
//do something with chunk
});
}).on("error", function(e){
console.log("Got error: " + e.message);
});
I want to know how to embed parameters in the body of POST request and how to capture them from the receiver module.
Would you mind using the request library. Sending a post request becomes as simple as
var options = {
url: 'https://someurl.com',
'method': 'POST',
'body': {"key":"val"}
};
request(options,function(error,response,body){
//do what you want with this callback functon
});
The request library also has a shortcut for post in request.post method in which you pass the url to make a post request to along with the data to send to that url.
Edit based on comment
To "capture" a post request it would be best if you used some kind of framework. Since express is the most popular one I will give an example of express. In case you are not familiar with express I suggest reading a getting started guide by the author himself.
All you need to do is create a post route and the callback function will contain the data that is posted to that url
app.post('/name-of-route',function(req,res){
console.log(req.body);
//req.body contains the post data that you posted to the url
});
If you want to use the native http module, parameters can be included in body this way:
var http = require('follow-redirects').http;
var fs = require('fs');
var options = {
'method': 'POST',
'hostname': 'example.com',
'path': '/foo.html',
'headers': {
},
'maxRedirects': 20
};
var req = http.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function (chunk) {
var body = Buffer.concat(chunks);
console.log(body.toString());
});
res.on("error", function (error) {
console.error(error);
});
});
var postData = "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"examplekey\"\r\n\r\nexamplevalue\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--";
req.setHeader('content-type', 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW');
req.write(postData);
req.end();

Categories