FormData change from multipart/form-data to form-urlencoded? - javascript

I am using the current javascript to post form data
var request = new XMLHttpRequest();
request.open("POST", "/validate",false);
request.send(new FormData(form)); // form is document.getElementById("#form")
With an expressjs backend using body-parser with following settings
app.use(parser.urlencoded({ extended: false }));
The form data is being posted properly with content-type to multipart/form-data; but according to body-parser they don't parse multipart content. How can i change the form submission to either urlencoded or json both of which can be parsed by the backend ?

Try add a header to request and convert data to url-encode format
function urlencodeFormData(fd){
var s = '';
function encode(s){ return encodeURIComponent(s).replace(/%20/g,'+'); }
for(var pair of fd.entries()){
if(typeof pair[1]=='string'){
s += (s?'&':'') + encode(pair[0])+'='+encode(pair[1]);
}
}
return s;
}
var request = new XMLHttpRequest();
request.open('POST', '/validate', false);
request.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
request.send(urlencodeFormData(new FormData(form)));

Related

XHR doesnt send json object

I have client - server express app. Im trying to send an XHR request from frontend to my controller, while passing json data. My frontend code looks like this:
function handle_login(){
var username_field = document.getElementById('input_username');
var pass = document.getElementById('input_password');
if(username_field.value!=null)console.log(username_field.value);
console.log(pass.value);
//window.location.href = "/loginAttempt/"+username.value+"-"+pass.value;
var xhr = new XMLHttpRequest();
var url = "/home_pogled";
xhr.open("GET", url, true);
xhr.setRequestHeader("Content-type", "application/json");
var data = {
username : username_field.value,
password : pass.value
}
var json = JSON.stringify(data);
xhr.send(json);
xhr.onload = function() {//ob uspesnem odgovoru
var responseText = xhr.responseText;
//console.log("Backend server response -" +responseText);
// uporabi odgovor
};
xhr.onerror = function() {
console.log('There was an error!');
};
}
I can send the request and i'm certain that data is written to the json object prior to sending it, but when i do consonle.log(req.body) in my controller upor receiving the request the body is empty "{}", where is should havec ontained the username and password values in a json objkect. What am i missing?
Client Side:
We can't send object in GET method, it should be query params like below snippet
let url = `/home_pogled?username=${username_field.value}&password=${pass.value}`;
xhr.open('GET', url);
Server side (express app):
In express js, we can get the query params in req.query
let username = req.query.username;
let password = req.query.password

req.body.username not outputting the correct value

sent data -
http.send(JSON.stringify(data));
outputting data -> {username: "dsa", password: "dsa"}
outputting JSON.stringify(data) ->
"{"username":"dsa","password":"dsa"}"
outputting req.body server side ->
{ '{"username":"dsa","password":"dsa"}': '' }
outputting req.body.username ->
undefined (expecting "dsa")
Body parser is installed and used with the app.
Javascript:
server.register = function(){
console.log('ran func');
usernameinput = document.getElementById("registerform").elements["username"].value
passwordinput = document.getElementById("registerform").elements["password"].value
var data = {
"username":usernameinput,
"password":passwordinput
}
http.open("post", server.regurl,true);
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.send(JSON.stringify(data));
}
server setup code contains the following:
const bodyParser = require('body-parser')
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }))
app.use(express.static(__dirname + '/')),
You stringified your JSON object so you can really adress its keys on server side - Its a plain string.
you could send it as is (a JSON object)
sent data - http.send(data);
or
sent data - http.send({payload: JSON.stringify(data)});
and then on server side
var x = JSON.parse(req.body.payload)
x.username;
UPDATE FOR ANSWER:
after reading a bit.
AJAX - Send a Request To a Server
and it says you should infact send a
string so it might be just a bad string format.
xhttp.open("POST", "demo_post2.asp", true);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send("fname=Henry&lname=Ford");
but JSON.stringify won't give you this 'URLish' syntax. maybe you should manipulate the string before you send it .
if you are using JSON.stringify you need something like this 'application/json'
server.register = function(){
console.log('ran func');
usernameinput = document.getElementById("registerform").elements["username"].value
passwordinput = document.getElementById("registerform").elements["password"].value
var data = {
"username":usernameinput,
"password":passwordinput
}
http.open("post", server.regurl,true);
http.setRequestHeader('Content-type', 'application/json')
http.send(JSON.stringify(data));
}

Sending a CSV file from browser to nodejs server

I am trying to send a csv file which is uploaded by the user, from browser to nodejs server for processing (file is over 50 mb, so the page becomes unresponsive). I'm using XMLHttpRequest for this purpose. I cannot find a solution to this. Any help is appreciated.
Javascript code
var csv = document.getElementById('inputFile').files[0];
var request = new XMLHttpRequest();
request.open("POST", "/handleFile", true);
request.setRequestHeader("Content-type", "text/csv");
request.onreadystatechange = function() {
if (request.readyState === XMLHttpRequest.DONE && request.status === 200) {
console.log("yey");
}
}
request.send(csv);
NodeJS server
var express = require('express')
var app = express()
var bodyparser = require('body-parser')
app.post('/handleFile', function(req, res) {
console.log(req.body); // getting {} empty object here....
console.log(req);
var csv = req.body;
var lines = csv.split("\n");
var result = [];
var headers = lines[0].split("\t");
for (var i = 1; i < lines.length; i++) {
var obj = {};
var currentline = lines[i].split("\t");
for (var j = 0; j < headers.length; j++) {
obj[headers[j]] = currentline[j];
}
result.push(obj);
}
fileData = result;
});
What did I do wrong? Is the XMLHttpRequest used incorrectly? or there is some other thing that i did not understand ? why is there no data in req.body even though its a post request.
Or is there any other way to send a csv/text file to nodejs server from front end.
This question is not a duplicate because, the body-parser i.e. the middleware responsible for parsing the req.body does not handle text/csv and multipart/form-data . The above link is not the correct solution.
So, after looking around, I found that the problem was not my XMLHttpRequest. The request was received by the server just fine, but the body-parser could not parse the text/csv and multipart/form-data content-type. Here is the step by step answer to this problem.
In the client/browser-end whenever you are sending a large file to the server, convert it into multipart/form-data . It is the correct way of sending a text/csv/anyfile to the server.
var csv=document.getElementById('inputFile').files[0];
var formData=new FormData();
formData.append("uploadCsv",csv);
var request = new XMLHttpRequest();
//here you can set the request header to set the content type, this can be avoided.
//The browser sets the setRequestHeader and other headers by default based on the formData that is being passed in the request.
request.setRequestHeader("Content-type", "multipart/form-data"); //----(*)
request.open("POST","/handleFile", true);
request.onreadystatechange = function (){
if(request.readyState === XMLHttpRequest.DONE && request.status === 200) {
console.log("yey");
}
}
request.send(formData);
So, this is how you'll send your http request to the nodejs server.
On Node js server: Normally for application/json or any other request type the body-parser would have worked fine. But for large data and files i.e. multipart/form-data body-parser cannot parse the req.body. Thus it will give req.body as {} (empty object).
Read about body-parser here.
So for these content-type you can use other middleware for handleling the request. Some are multer,multiparty,busboy etc. I used multer.
Here is the code snipet.
//EXPRESS
var express = require('express')
var app = express()
var config=require('./config.js');
//multer
var multer = require('multer');
var upload = multer();
app.post('/handleFile',upload.single('uploadCsv'), function(req, res, next) {
// req.file is the `uploadCsv` file
// req.body will hold the text fields, if there were any
console.log(req.file);
// the buffer here containes your file data in a byte array
var csv=req.file.buffer.toString('utf8');
});
NOTE:
This will still give you an error in nodejs server.
hint: It has something to do with the line (*). Try removing it and see what happens.
Google the rest ;)

How do you send a post via XMLhttprequest to my own Node server in vanilla javascript?

I am trying to send data to node via a XMLhttprequest. The data looks like this (/q/zmw:95632.1.99999.json). My connection to Node is correct, however, I was getting an empty object so I set the headers to Content-Type application/json and then stringified the data. However Node gives me a Unexpected token " error. I presume it is because of the string, however, if I don't stringify the data then it errors out because of the "/" in the data. How do i properly send the data using pure Javascript. I want to stay away from axios and jquery because I want to become more proficient in vanilla javascript. I will make the final call to the api in node by assembling the url prefix and suffix.
Here is my code:
function getCityForecast(e){
//User selects option data from an early JSONP request.
var id = document.getElementById('cities');
var getValue = id.options[id.selectedIndex].value;
//Assembles the suffix for http request that I will do in Node.
var suffix = getValue + ".json";
var string = JSON.stringify(suffix);
console.log(suffix);
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://localhost:3000/", true);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.send(string);
}
Node.js code:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var path = require('path');
var request = require('request');
var http = require('http');
// ****************** Middle Ware *******************
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(express.static(__dirname + '/public'));
app.post('/', function(req, res){
console.log('working');
console.log(req.body);
});
app.listen(3000, function() { console.log('listening')});
I figured it out my mistake and this was my problem. I was trying to send a string instead of an object. So it wasn't proper JSON like this:
var string = JSON.stringify(suffix);
To remedy the situation I added:
var newObj = JSON.stringify({link : suffix});
This allowed my post to be successful because I was now sending an object hence the word Javascript Object Notation.
This is working for me, at the moment. The REST API I'm hitting requires a token. Yours might not, or it might be looking for some other custom header. Read the API's documentation. Note, you might need a polyfill/shim for cross browser-ness (promises). I'm doing GET, but this works for POST, too. You may need to pass an object. If you're passing credentials to get a token, don't forget window.btoa. Call it like:
httpReq('GET', device.address, path, device.token).then(function(data) {
//console.log(data);
updateInstrument(deviceId,path,data);
}, function(status) {
console.log(status);
});
function httpReq(method, host, path, token) {
if(method === "DELETE" || method === "GET"|| method === "POST" || method === "PUT" ){
var address = 'https://' + host + path;
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open(method, address, true);
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader ("X-auth-token", token);
//xhr.setRequestHeader ("Content-Type", "application/x-www-form-urlencoded");
xhr.onload = function() {
var status = xhr.status;
if (status == 200 || status == 201 || status == 202) {
resolve(xhr.response);
}
// this is where we catch 404s and alert what guage or resource failed to respond
else {
reject(status);
}
};
xhr.send();
});
} else {
console.log('invalid method');
}
};

send url with parameters using ajax

I want to send a url with parameters using ajax following is the data I want to sent http://sample-domain.com/send-email.php?pid=3224&act=report but it sends only http://sample-domain.com/send-email.php
Following is my ajax code
<script>
window.addEventListener("load", function(){
var x=document.getElementsByTagName("a");
for(var i=0; i<x.length; i++){
x[i].addEventListener("click", nextlocation);
};
});
function nextlocation(evt){
var y = String(this.getAttribute("href"));
alert(y);
httpRequest = new XMLHttpRequest();
httpRequest.open('POST', 'setnext.php');
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
httpRequest.send('next='+y);
};
</script>
and in setnext.php
<?php
session_start();
$_SESSION['next']=$_POST['next'];
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
You've said that you are encoding the data using the application/x-www-form-urlencoded format.
But here:
httpRequest.send('next='+y);
You are just putting an = between the key and the value without taking into consideration any of the other rules for application/x-www-form-urlencoded data.
One of those rules is that & separates key=value pairs … and you have a & in your data.
You have to encode your data properly.
httpRequest.send('next=' + encodeURIComponent(y));

Categories