Sending a CSV file from browser to nodejs server - javascript

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

Related

How do I res.send object to the backend from the front end?

I am trying to communicate with the frontend to the backend. currently, I have the backend sending an expression to the frontend, and the frontend computes it. from there I want the frontend to send the computed answer back to the backend.
Forexample:
the backend sends "2+2="
the frontend computes that 2+2 = 4
the frontend then sends the answer 4 to the backend
the backend logs the answer 4
Front-end
var XMLHttpRequest = require('xhr2');
const URL = "http://localhost:5000/"
let firstNumber = Math.floor(Math.random() * 10);
let secondNumber = Math.floor(Math.random() * 10);
const express = require('express');
const app = express();
// excecuting random addition
const finalExpression = firstNumber + "+" + secondNumber + "="
console.log(finalExpression);
var xhr = new XMLHttpRequest();
xhr.open("POST", URL, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
expression: finalExpression
}))
Back-end:
const express = require('express')
const app = express()
app.use(express.json())
app.post('/', (req, res) => {
console.log(req.body.expression);
arr = req.body.expression.split("")
console.log(parseInt(arr[0]) + parseInt(arr[2]))
// res.send(parseInt(arr[0]) + parseInt(arr[2]))
})
app.listen(5000, () => console.log())
as you can see, I tried res.send in the frontend to the backend.
You appear to have mixed things up a little.
You can't use express on the front-end - it's a node application. You shouldn't need to use XMLHttpRequest on the server at all. express will handle all the routing for you.
You should use fetch on the front-end to get/post requests to the server (I've used async/await here).
It might look a little more like this.
Server:
// Send an expression to the front-end
app.get('/getExpression', (req, res) => {
res.send(expression);
});
app.post('/postResult', (req, res) {
const result = res.body;
// Calculate whether the result is correct,
// and then send the answer back
res.send(isResultCorrect);
});
Client:
// To get the expression from the server
const response = await fetch('/getExpression');
const expression = await response.text();
// To post the result back to the server
const options = { type: 'POST', body: result };
const response = await fetch('/postResult', options);
const isResultCorrect = await response.text();
You invert frontend and backend :) It is the frontend that sends the XMLHTTPREQUEST and it is the server that processes the request and returns the response.
This being said, using res.send is the right solution to return a response. You did the right thing in BACKEND. Therefore, you can uncomment the // res.send(parseInt(arr[0]) + parseInt(arr[2])) and leave the backend code as it is.
What is missing in the FRONTEND is a code to listen to and handle this response :
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
console.log(xhr.response);
}
}
Add it after var xhr = new XMLHttpRequest();
Your code should then look like this :
var xhr = new XMLHttpRequest();
// New code added here
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
// Handle the response (ex: console.log it)
console.log(xhr.response);
}
}
xhr.open("POST", URL, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
expression: finalExpression
}))

Received data through a POST Request always empty

I have server and a client the server uses node js the client send requests to the sever and the server should act accordingly.
However I came across a little bit of a confusing behavior and i want to know why its behaving like that!
The thing is when i send a json array or Object the received data by the server is always empty for some reason.
Here is the code of the request that raises the problem:
function Save()
{ // saves the whole global data by sending it the server in a save request
if( global_data.length > 0)
{
var url = "http://localhost:3000/save";
var request = new XMLHttpRequest();
request.open("POST", url, true);
request.setRequestHeader("Content-Type", "application/json");
request.onreadystatechange = function () {
if (request.readyState === 4 && request.status === 200) {
console.log(this.responseText);
}
};
let object={ id: "101.jpg", RelativePath: "images/101.jpg", size: 61103 }; // this just an exemple of data
let data_json = JSON.stringify(object);
request.send(data_json);
}
else
{
console.log("Nothing to save");
}
}
And Here is the server code related to this request:
const server=http.createServer(onRequest)
server.listen(3000, function(){
console.log('server listening at http://localhost:3000');
})
function onRequest (request, response) {
/*function that handles the requests received by the server and
sends back the appropriate response*/
/*allowing Access-Control-Allow-Origin since the server is run on local host */
response.setHeader('Access-Control-Allow-Origin', '*');
response.setHeader('Access-Control-Request-Method', '*');
response.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
response.setHeader('Access-Control-Allow-Headers', '*');
console.log("a request received :" ,request.url);
let parsed_url = url.parse(request.url);
if(parsed_url.pathname == '/save')
{
console.log("Proceeding to save state : ...");
let received_data = '';
request.on('data', function(chunck) {
received_data += chunck;
console.log("another line of data received");
});
request.on('end', function() {
console.log(received_data); // why is this empty (my main problem)?
let jsondata = JSON.parse(received_data); // here raises the error since the received data is empty
console.log(jsondata);
response.writeHeader(200,{"content-Type":'text/plain'});
response.write("SAVED!");
response.end()
});
}
}
Just if anyone got the same problem: for me I couldn't solve it directly so I was forced to use query-string in order to parse the data instead of json.parse it seems the data received emptiness was related to the failure of the JSON parser somehow. so I installed it with npm install querystring and used const qs = require('querystring'); in order to invoque the parser by calling qs.parse(received_data.toString());.
Hope this helps anyone who got stuck in the same situation.

POST request body is empty on server

I am trying to make an AJAX request from the client side javascript using XMLHttpRequest. Following is the code for it:
document.getElementById('myform').onsubmit=function(){
var http = new XMLHttpRequest();
var text = document.getElementById('myinput').value;
console.log(text);
http.onreadystatechange = function(){
if(http.readyState === 4 && http.status === 200){
location.reload();
}
};
http.open('POST','/todo',true);
http.setRequestHeader("Content-Type", "application/json");
var obj = {
item:text
};
http.send(JSON.stringify(obj));
}
This works fine without anny errors. However, on the server side, when I try to log the request body to the console, it shows as an empty object. Can someone help me with this? Following is the server side code for handling the post request:
app.post('/todo',urlencodedParser, function(req,res){
console.log(req.body); // This logs an empty object to the console!
newItem = Todo(req.body);
newItem.save(function(err,data){
if(err) throw err;
res.json(data);
});
});
JSON encoding and URL encoding are different.
If you wish to send the data with JSON encoding, then you must receive it with the appropriate middleware:
const bodyParser = require('body-parser');
app.post('/todo', bodyParser.json(), function(req,res){
console.log(req.body); // This logs an empty object to the console!
newItem = Todo(req.body);
newItem.save(function(err,data){
if(err) throw err;
res.json(data);
});
});
It most likely worked with jQuery because urlencoding is default behavior for $.post.

Displaying Data on Website from Node.js (Without Frameworks)

I have a Node.js webserver and I am fetching data from a mysql Server. The fetched Data needs to be displayed now in the frontend as HTML. I am not allowed to use any 3rd Party node.js/JavaScript framework's.
I'm new to Webserver development and i'm having a hard time figuring out how to "transport" the Backend Data to the Frontend.
I have 2 Ideas in my mind but dont know what's the right way to approach this problem...
Send Data via JSON to Client and process it with JavaScript. (Possible? and if yes how?)
Before sending the HTTP response, parse the HTML and insert the data. (Complicated without using Frameworks and too costly ?)
What would be the right way to solve this problem ?
Any Help would be appreciated. Thank's.
Solved it like this:
app.js
var http = require('http');
var url = require('url');
var server = http.createServer(function(req, res) {
var q = url.parse(req.url, true);
if(q.filename == "command"){
res.writeHead(200, {'Content-Type':'application/json'});
return res.end(some_json);
}
}
index.html
<script>
xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST","http://localhost:8000/command", true);
xmlhttp.onreadystatechange=function(){
if (xmlhttp.readyState==4 && xmlhttp.status==200){
//Process Data
var jsonObj = JSON.parse(xmlhttp.responseText);
document.getElementById("test").innerHTML = jsonObj;
}
}
xmlhttp.send();
</script>
<div id="test"></div>
Something like this?
const http = require('http');
const util = require('util');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
mysql.query("select * from table").then(rows => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
res.end(`<html><head></head><body>${util.inspect(rows)}</body></html>`);
})
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});

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

Categories