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.
Related
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.
There is a node.js server and I'm going to call my web api controller when a client connected with node.js server using a websocket. Im' using socket.io to connect client with node.js server, then node.js server sends a xhr POST request to web api controller. but getting the response as,
"{"Message":"No HTTP resource was found that matches the request URI 'http://localhost:4928/api/Player'.","MessageDetail":"No action was found on the controller 'Player' that matches the request."}"
Web API Method
public class PlayerController : ApiController
{
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
public string Post(string value)
{
return value;
}
}
Node.js
var app = require('express')();
var http = require('http').Server(app);
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
var xhr = new XMLHttpRequest();
var querystring = require('querystring');
var io = require('socket.io')(http);
io.on('connection', function (socket) {
console.log('A user connected ' + socket.handshake.address);
PostRequest(socket.handshake.address);
//Whenever someone disconnects this piece of code executed
socket.on('disconnect', function () {
console.log('A user disconnected ' + socket.handshake.address);
});
});
function PostRequest(data) {
var url = "http://localhost:4928/api/Player";
var params = "value=" + data;/* querystring.stringify({ "value": data })*/
xhr.open('POST', url, true);
xhr.onreadystatechange = function () {//Call a function when the state changes.
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responseText);
}
console.log(xhr.responseText);
}
xhr.send(querystring.stringify({ value: "sss" }));
}
http.listen(3000, function () {
console.log('listening on *:3000');
});
Anyway this is working when I'm call the get method sending a xhr get request
You need to inform Web API to look for the value parameter in the Request body since you're not sending data via query string. Try modifying your Post action signature:
public string Post([FromBody]string value)
{
...
}
My Ajax request is not receiving proper response! It always enters readyState '4' with response status '0' ??
Client Code:
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function(){
if(xhttp.readyState == 4 && xhttp.status == 200){
document.getElementById("lastNameLabel").innerHTML = "response recieved!";
const responseJSON = JSON.parse(xhttp.responseText);
if(responseJSON.emailTaken == "false"){
window.location = server+"/client/home.html";
}
}
};
xhttp.open("POST", server+"/signUp", true);
xhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhttp.send("email="+email);
server Code (Node.js + Express):
app.post('/signUp', (req, res) => {
res.end("it worked!!");
});
I Know my Server is processing the request since I see the url call, but the response never reaches the html client!!. I'm Super Stuck!
Putting #jaromanda-x's suggestion as an answer, you need to enable CORS in your server.
This is how it's done:
var cors = require('cors');
app.use(cors());
For more info, refer this express doc about it.
You have to have your NodeJS server reply with an HTTP response message that includes a status code and reason phrase such as
res.status(200).send({ status: 'ok' });
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');
}
};
I am running a nodejs server to run my website, and I want the backend server to make a call to an api on an external server. I tried the following, basic and straightforward method:
router.post('/calculate', function (req, res) {
var data = /*some json object*/
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", "some.server/pricing");
xmlhttp.setRequestHeader("Content-Type", "application/json");
xmlhttp.send(JSON.stringify(data));
xmlhttp.onreadystatechange = function() {
if(xmlhttp.status == 200)
{
var str = xmlhttp.responseText.toString().trim()
dd = JSON.parse(str);
res.send(dd);
//res.end();
}
};
});
When I run this I get:
_http_outgoing.js:346
throw new Error('Can\'t set headers after they are sent.');
^
Error: Can't set headers after they are sent.
The issue seems to be in res.send(dd);
EDIT:
Upon further investigation, it seems like xmlhttp.onreadystatechange happens twice with status 200, and res.send is called twice. I created a temporary hack to fix this using a boolean flag, what is the rpoper nodejs way to fix this?
What is the most straightforward way of making such a call in nodejs? I want this done on the server side. I am not using any libraries like express. Thanks
Easy do it with request package
var request = require('request');
request({
url: 'some.server/pricing',
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
form: data
}, function (err, res, body) {
if (err) res.send(err)
else res.send(body)
});
After a lot more investigation, I found out that res.send was being called twice. The reason this was happening was because the xmlhttp object changes its state several times:
http://www.w3schools.com/ajax/ajax_xmlhttprequest_onreadystatechange.asp
I fixed the code to:
if (xhttp.readyState == 4 && xhttp.status == 200)
Now everything works properly.