Long polling with Node.js and ajax - javascript

I have following server code.
var http = require('http');
var mysql = require('mysql');
var querystring = require('request');
var util = require('util');
var url = require('url');
var singer_name;
var currentmodif, lastmodif;
var requests=[];
var response;
var connection = mysql.createConnection({
host : 'localhost',
user : 'someone',
password : 'xxxxxxx',
database : 'rest', //mysql database to work with (optional)
});
connection.connect(); //connect to mysql
connection.query('SELECT * FROM musics WHERE id=1', function(err, rows, fields) {
if (err) throw err;
singer_name=rows[0].singer_name;
currentmodif=rows[0].time_added;
});
http.createServer(function (req, res) {
console.log('request received');
requests.push({
response: res,
timestamp: new Date().getTime()
});
if(req.method=='GET'){
var url_parts = url.parse(req.url,true);
lastmodif = url_parts.query.timestamp;
}
//check_update(req, res);
}).listen(9000);
setInterval(function() {
var expiration = new Date().getTime() - 30000;
for (var i = requests.length - 1; i >= 0; i--) {
//console.log("Request timestamp: "+requests[i].timestamp+" Expiration : "+expiration);
response = requests[i].response;
if (requests[i].timestamp < expiration) {
console.log("The condition is met");
response.writeHead(200, {
'Content-Type' : 'text/plain',
'Access-Control-Allow-Origin' : '*'
});
// return response
response.write('_testcb(\'ok\')', 'utf8');
response.end();
//break;
}
}
connection.query('SELECT * FROM musics WHERE id=1', function(err, rows, fields) {
if (err) throw err;
currentmodif=rows[0].time_added;
//console.log("currentmodif: "+currentmodif+" lastmodif: "+lastmodif);
if (currentmodif > lastmodif){
singer_name=rows[0].singer_name;
var _arrays = {'singer_name': singer_name, 'time': currentmodif}
var data = "_testcb"+"("+JSON.stringify(_arrays)+")";
response.writeHead(200, {
'Content-Type' : 'text/plain',
'Access-Control-Allow-Origin' : '*'
});
if (response.end(data))
console.log("Response successfully sent");
//return false;
}
});
}, 2000);
and Client code:
<html>
<head>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<title>Node.js Ajax test</title>
</head>
<body>
</body>
<script>
var timestamp = "1380020402";
function callNode() {
var time = "1380020402";
$.ajax({
url: 'http://xx.xxx.xx.xxx:9000/',
dataType: "jsonp",
data: {"timestamp":timestamp},
type: 'POST',
jsonpCallback: "_testcb",
cache: false,
timeout: 35000,
success: function(response, code, xhr) {
if ('ok' == response) {
callNode();
return false;
}
console.log(response);
timestamp = response.time;
// make new call
callNode();
},
error: function(jqXHR, textStatus, errorThrown) {
console.log('error ' + textStatus + " " + errorThrown);
}
});
}
$(function () {
callNode();
});
</script>
</html>
I am trying to do a long polling. So until a data in database is updated, the response to ajax request should be paused but the above code is not working. I am making the ajax request from different domain and therefore using jsonp.
Exact problem is that currently when the data is changed in database the response doesn't get sent. It works every now and then but it is not consistently reliable.
Another problem is that the code block for time out is not working. If the request is 30 seconds old then a blank response should be sent in order to avoid the timeout from ajax.
If someone can help then I would appreciate.
Cheers.

I have figured this out. Amended code that work is as below:
Client side:
<html>
<head>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<title>Node.js Ajax test</title>
</head>
<body>
</body>
<script>
var timestamp;
function callNode() {
$.ajax({
url: 'http://xx.xxx.xx.xxx:9000/',
dataType: "jsonp",
data: {"timestamp":timestamp},
//type: 'POST', //don't need this with jsonp
jsonpCallback: "_testcb",
cache: false,
timeout: 35000,
success: function(response, code, xhr) {
if ('ok' == response) {
console.log(response);
callNode();
return false;
}
console.log(response);
timestamp = response.time;
// make new call
callNode();
},
error: function(jqXHR, textStatus, errorThrown) {
console.log('error ' + textStatus + " " + errorThrown);
}
});
}
$(function () {
setTimeout(callNode, 1); //call function with setTimeout in order to avoid ugly constant browser loading
});
</script>
</html>
Server Side (server.js):
var http = require('http');
var mysql = require('mysql');
var util = require('util');
var url = require('url');
var singer_name, currentmodif, lastmodif, request, response, time_of_request;
//var requests=[];
var connection = mysql.createConnection({
host : 'localhost',
user : 'someone',
password : 'xxxxxx',
database : 'rest', //mysql database to work with (optional)
});
connection.connect(); //connect to mysql
connection.query('SELECT * FROM musics WHERE id=1', function(err, rows, fields) {
if (err) throw err;
singer_name=rows[0].singer_name;
currentmodif=rows[0].time_added;
});
http.createServer(function (req, res) {
request = req;
response = res;
time_of_request = new Date().getTime();
console.log('request received');
if(req.method=='GET'){
var url_parts = url.parse(req.url,true);
lastmodif = url_parts.query.timestamp;
}
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
//checkupdate();
}).listen(9000);
var response;
function checkupdate() {
var expiration = new Date().getTime() - 30000;
//for (var i = requests.length - 1; i >= 0; i--) {
//console.log("Request timestamp: "+time_of_request+" Expiration : "+expiration);
if (time_of_request < expiration) {
console.log("The condition is met");
// return response
response.write('_testcb(\'ok\')', 'utf8');
response.end();
}
//}
connection.query('SELECT * FROM musics WHERE id=1', function(err, rows, fields) {
if (err) throw err;
currentmodif=rows[0].time_added;
if (lastmodif == undefined)
lastmodif = 0;
console.log("currentmodif: "+currentmodif+" lastmodif: "+lastmodif);
if (currentmodif > lastmodif){
singer_name=rows[0].singer_name;
var _arrays = {'singer_name': singer_name, 'time': currentmodif}
var data = "_testcb"+"("+JSON.stringify(_arrays)+")";
//response.writeHead(200, { 'content-type':'application/json',
//'Access-Control-Allow-Origin' : '*'});
//response.write(data);
response.end(data);
console.log("Response successfully sent");
//return false;
}
});
};
setInterval(checkupdate, 2000);
The problem was with the server side. The response object was not available (it was undefined) when server wanted to reply and therefore the response was not being sent. I may have overlooked the error in the node.js's console.
This is almost a complete example of long polling with node.js with MYSQL database. This script will wait for fresh data to become available before replying to the ajax request. If fresh data (in MYSQL) is not available within 30 seconds of the request then a fake reply is made so that the request does not time out. There is a condition in ajax's success callback that re-initiates this ajax request when this demo response is received, therefore making this an infinite loop.
I have successfully tested code above and it seems to work fine. I ran the script and then updated the data in my database (mainly the time_added field) and this triggered a reply to my waiting ajax call with new data from node.js's server.
I hope this code helps someone out there.
Checkout tutorial here for further explanation: http://www.sahilsaid.com/blog/long-polling-node-js-mysql-database-ajax/

Related

How to post data from my html page to a listener?

I'm currently designing a UI for an Automated Parking System. I currently need to test if my page sends out data from a form by sending it to a listener. I currently have this code but I'm not sure why it isn't working. Any help would be greatly appreciated.
This is my code that sends the data to a local listener.
<script>
var INPARK = {cardID: $("#ticket_num").val(), lift: 1, floor: 1};
$.ajax({
type:"POST",
url: '192.168.150.148:5007',
contentType:"application/json",
data: JSON.stringify(INPARK)
});
</script>
This is the listener code.
var HOST = '192.168.150.148'; // This should be your IP of 192.168.150.XXX
var PORT = 5007;
var http = require('http');
http.createServer(function (req, res) {
// Only listen for POST requests
if (req.method === 'POST') {
var buffer = '';
req.on('data', function (chunk) {
buffer += chunk;
});
req.on('end', function () {
var path = req.url.substring(0, req.url.indexOf('/', 1)).toUpperCase();
var json;
try {
json = JSON.parse(buffer);
} catch (err) {
//
}
if (path === '/INPARK') {
// Handle INPARK request
console.log(json);
res.write('inpark results');
} else if (path === '/OUTPARK') {
// Handle OUTPARK request
console.log(json);
res.write('outpark results');
} else {
// Do nothing - Bad request
res.write('BAD REQUEST');
}
// Close the connection
res.end();
});
}
}).listen(PORT, HOST, function () {
console.log('Listening at %s:%s', HOST, PORT);
});
Your ajax request is most likely going from port 80 or 443 to 5007, which is a cross domain request, hence it will fail,
If you want to resolve this issue, read up on CORS:
https://en.wikipedia.org/wiki/Cross-origin_resource_sharing,
and JSONP:
https://en.wikipedia.org/wiki/JSONP

io.connect: io is not defined but socket.io is loaded

I have built a node.js server that provides a client.html page with a list of messages from a mysql db. I can't make it work using an ajax call.
The client.html page is this:
<time></time>
<div id="container">Loading ...</div>
<script src="http://oclock.dyndns.org:8000/socket.io/socket.io.js"></script>
<!--<script src="socket.io/socket.io.js"></script>-->
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
// create a new websocket
var socket = io.connect('http://oclock.dyndns.org:8000');
// on message received we print all the data inside the #container div
socket.on('notification', function (data) {
var msgs = '<div>';
$.each(data.flashmsgs,function(index,flashmsg){
msgs += "<b>Messaggio inviato da " + flashmsg.created_by + "</b><br>";
msgs += flashmsg.testo;
});
msgs += '</div>';
$('#container').html(msgs);
$('time').html('Last Update:' + data.time);
});
</script>
and the code for the ajax call is the following:
(function nodeLoader(){
$.ajax({
url: "client.html",
method: "get",
data: {hk: hk },
success: function(data){
$('#messaggi').html(data);
}
});
})();
The socket.io code is loaded but I get an error on io.connect: io is not defined. Same issue if i change the url from client.html to http://oclock.dyndns.org:8000 (the url of the node.js server that is listening for requests).
Any help is appreciated!
EDIT:
server.js
var hwkey;
var app = require('http').createServer(handler),
io = require('socket.io').listen(app),
url = require('url'),
fs = require('fs'),
mysql = require('mysql'),
connectionsArray = [],
connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'flipper',
database: 'oclock',
port: 3306
}),
POLLING_INTERVAL = 3000,
pollingTimer;
// If there is an error connecting to the database
connection.connect(function(err) {
// connected! (unless `err` is set)
if (err) {
console.log(err);
}
});
// creating the server ( localhost:8000 )
app.listen(8000);
function handler(req, res) {
var origin = (req.headers.origin || "*");
if (req.method.toUpperCase() === "OPTIONS"){
res.writeHead(
"204",
"No Content",
{
"access-control-allow-origin": origin,
"access-control-allow-methods": "GET, POST, PUT, DELETE, OPTIONS",
"access-control-allow-headers": "content-type, accept",
"access-control-max-age": 10, // Seconds.
"content-length": 0
}
);
return( res.end() );
}
console.log("INCOMING REQUEST: "+req.method+" "+req.url);
req.parsed_url = url.parse(req.url, true);
var getp = req.parsed_url.query;
hwkey = getp.hk;
fs.readFile(__dirname + '/client.html', function(err, data) {
if (err) {
console.log(err);
res.writeHead(500);
return res.end('Error loading client.html');
}
res.writeHead(
200,
{
"access-control-allow-origin": origin,
"content-length": data.length
}
);
res.end(data);
});
}
function pollingLoop(){
// Doing the database query
var query = connection.query('SELECT id, testo, created_by FROM flashmsgs WHERE hwk="'+hwkey+'" AND letto="0"'),
//var query = connection.query('SELECT max(id), testo, created_by FROM flashmsgs'),
flashmsgs = []; // this array will contain the result of our db query
// setting the query listeners
query
.on('error', function(err) {
// Handle error, and 'end' event will be emitted after this as well
console.log(err);
updateSockets(err);
})
.on('result', function(flashmsg) {
// it fills our array looping on each user row inside the db
flashmsgs.push(flashmsg);
})
.on('end', function() {
// loop on itself only if there are sockets still connected
if (connectionsArray.length) {
pollingTimer = setTimeout(pollingLoop, POLLING_INTERVAL);
updateSockets({
flashmsgs: flashmsgs
});
} else {
console.log('The server timer was stopped because there are no more socket connections on the app')
}
});
};
// creating a new websocket to keep the content updated without any AJAX request
io.sockets.on('connection', function(socket) {
console.log('Number of connections:' + connectionsArray.length);
// starting the loop only if at least there is one user connected
if (!connectionsArray.length) {
pollingLoop();
}
socket.on('disconnect', function() {
var socketIndex = connectionsArray.indexOf(socket);
console.log('socketID = %s got disconnected', socketIndex);
if (~socketIndex) {
connectionsArray.splice(socketIndex, 1);
}
});
console.log('A new socket is connected!');
connectionsArray.push(socket);
});
var updateSockets = function(data) {
// adding the time of the last update
data.time = new Date();
console.log('Pushing new data to the clients connected ( connections amount = %s ) - %s', connectionsArray.length , data.time);
console.log(hwkey);
// sending new data to all the sockets connected
connectionsArray.forEach(function(tmpSocket) {
tmpSocket.volatile.emit('notification', data);
});
};
console.log('Please use your browser to navigate to http://localhost:8000');
Okay, I misunderstood at first. I just investigated your live app and it appears your ajax call is pulling down an entire html document.
If you're loading markup via ajax and then inserting into the existing page, you don't want a full HTML document. Just send down the body content.
Also, the socket.io script reference should ideally be on the parent page, not the page loaded via ajax.

nodejs hapiJs: Sending, receiving data from client

I have the following files; client.js and server.js. I want to send data to my server, using ajax. I manage to send the searched username, but the domain is received on the server as undefined. I am not sure if I am missing something on the client side, or the server side, or both?
On the server side, my function should be a generic function to allow it to receive any domain and the issue the request on that domain.
Can anyone help out please?
Cliente:
$(document).ready(function(){
console.log("Ready!");
var domains=[ ]; //pass domain names into array for easier iteration
domains.push($(".facebook").find("a").text());
domains.push($(".github").find("a").text());
domains.push($(".twitter").find("a").text());
domains.push($(".instagram").find("a").text());
domains.push($(".pinterest").find("a").text());
console.log(domains);
$("#searchbutton").on('click', function(event){
var username = $("#searchname").val().trim(); // store value from searchbox
console.log(username);
if(username === ""){
event.preventDefault();
}
if(username){
var newhtml = "<p>";
newhtml += username;
newhtml += "</p>";
$(".username").html(newhtml);
$(".username").remove("newhtml");
var domainCheck = function(domainName){
$.ajax({
url: "/"+username,
type: "get",
data: {domainName: domainName, username: username},
success: function(response){
console.log(domainName);
console.log(response);
}
});
};
//send ajax request to server for each domain name to check for username availability
var len = domains.length;
for(var i = 0; i<len; i++){
domainCheck(domains[i]);
console.log(domains[i]+'\n');
}
}
});
});
Server:
var Hapi = require('hapi');
var request = require('request');
var server = Hapi.createServer('localhost', 8080);
var routes =[
{
path: "/",
method: "GET",
handler: function (req, reply){
console.log("Home page loaded and runnning!");
reply.file('index.html');
}
},
{
path: '/{username}',
method: 'GET',
handler: function (req, reply){
// this is not working. the domain name is not being received from the client side. instead its passing undefined!
request('http://www.'+ req.domain.domainName +'.com/' + req.params.username, function(error, response, body){
console.log("Request received");
console.log(response.statusCode);
if ( response.statusCode === 404 ) {
console.log( "Username " + req.params.username + " is available on " + req.domain.domains);
reply({"available":"yes"});
}
if ( response.statusCode === 200 ) {
console.log( "Username " + req.params.username + " is already taken on " + req.domain.domains);
reply({"available":"no"});
}
});
}
},
{
method: 'GET',
path: '/static/{param*}',
handler: {
directory: {
path: 'static'
}
}
}
];
server.route(routes);
server.start(function() {
console.log("Server started", server.info.uri);
});
module.exports = server;
Change req.domain.domainName to req.query.domainName. When you access request data, you need to specify whether it is in the query, in the payload, etc.

nodejs https callback not updating global variable [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 9 years ago.
I'm setting up a quick proxy server in nodejs to proxy a API request for an Angular application. The proxy endpoint is a service I do not control and does not support CORS or JSONP. For testing, I setup a dummy http server in the code example below, but in reality this is a remote domain.
I'm pretty sure my problem is due to asynchronous processing of nodejs, but I don't know how to solve this. My generic makeRequest() function seems to work ok, it gets the expected response back from the remote server. I can see the resultData string in the on('data') and on('end') event handlers with success. However, I don't know how to get the response back to the browser inside restify's req.json() method.
Help!
var restify = require('restify');
var querystring = require('querystring');
var https = require('https');
var http = require('http');
var port = '8080';
var server = restify.createServer({
name : "ProxyService"
});
var responseData = '';
// Generic request function
function makeRequest(host, endpoint, method, data, headers) {
var dataString = JSON.stringify(data);
var options = {
host: host,
path: endpoint,
method: method,
headers: headers
};
var req = https.request(options, function proxyrespond(res) {
res.on('data', function(data) {
console.log("DATA----", data);
responseData += data;
});
res.on('end', function() {
//probably need to do something here
});
});
req.end();
req.on('error', function(e) {
console.error(e);
});
console.log("OPTIONS: ", options);
console.log("DATA: ", responseData);
req.write(dataString);
req.end();
};
server.get('/getlist', function respond(req, res, next){
var headers = {'Connection': 'close',
'Content-Type': 'application/json' };
var host = 'localhost:9000';
var endpoint = '/getlist';
var auth = {auth-id: '12345', auth-token: '6789'}
var data = req.data || '';
// add authentication parms to the endpoint
endpoint += '?' + querystring.stringify(auth);
// if the request has headers, add them to the object
for (var key in res.headers) {
headers[key] = rest.headers[key];
};
makeRequest(host, endpoint, 'GET', data, headers);
res.headers = {Connection: 'close'};
res.json( responseData );
return next();
});
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied!' + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9000);
server.listen(port, function(){
console.log('%s listening at %s ', server.name , server.url);
});
Return via a callback function:
// Generic request function
function makeRequest(host, endpoint, method, data, headers, callback) {
.........
var req = https.request(options, function proxyrespond(res) {
// DO NOT declare responseData as global variable
var responseData = '';
res.on('data', function(data) {
responseData = responseData + data;
});
res.on('end', function() {
// RETURN VIA CALLBACK
callback(responseData)
});
});
.........
};
server.get('/getlist', function respond(req, res, next){
.........
makeRequest(host, endpoint, 'GET', data, headers, function (responseData) {
res.headers = {Connection: 'close'};
res.json( responseData );
return next();
});
});

Node.js - How to initialise/define req.body?

I get the error - "Cannot read property 'score' of undefined" at "var score - req.body.score". In order to do this I'm guessing I need to define and/or initialise 'req.body' (I'm pretty new to Node.js), any idea how I do this?
Here's my Node.JS code as it stands:
var http = require('http');
var express = require('express');
console.log('Game server running...');
http.createServer(function (req, res) {
console.log('Player submitted high-score:');
var score = req.body.score;
console.log(score);
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('_testcb(\'"Your high-score has been submitted."\')');
}).listen(80);
Below is the HTML with the input text field and a submit button:
Your score: <input id="score" name="score" type="text"></input>
<button id="SubmitBtn" type="submit">Submit</button>
And also below is the JavaScript within the HTML (Just in case it helps answer my question):
<script>
$(document).ready(function() {
$('#SubmitBtn').click(function (event) {
$.ajax({
url: 'http://localhost',
data: { score : $("input[name='score']").val() },
dataType: "jsonp",
jsonpCallback: "_testcb",
cache: false,
timeout: 5000,
success: function(data) {
$("#test").append(data);
},
error: function(jqXHR, textStatus, errorThrown) {
alert('Error connecting to the Node.js server... ' + textStatus + " " + errorThrown);
}
});
});
});
Basically, I want to get the input from a input text field called 'score' from a HTML doc, but getting the error "Cannot read property 'score' of undefined" at 'var score - req.body.score'. Guessing I need to initialise/define 'req.body somewhere but I don't know how? Can anyone help me out?
Also, I've found this online about initialising/defining 'res.body', could be useful??
req.on('response', function (res) {
res.body = "";
res.on('data', function (chunk) {
res.body += chunk;
});
res.on('end', function () {
console.log(res.body);
});
});
Thanks
I don’t know whether some “middleware” provides req.body, but to continue down that path:
var http = require('http');
var express = require('express');
var qs = require('querystring');
console.log('Game server running...');
http.createServer(function (req, res) {
console.log('Player submitted high-score:');
var bodyParts = [];
req.on("data", function(part) {
bodyParts.push(part);
});
req.on("end", function() {
var body = Buffer.concat(bodyParts).toString("utf8");
var data = qs.parse(data);
var score = data.score;
console.log(score);
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('_testcb(\'"Your high-score has been submitted."\')');
});
}).listen(80);
The request.body property is populated by the bodyParser middleware, so you have to include that in the node.js app as well
app.use(express.bodyParser())
so
var http = require('http');
var express = require('express');
var app = express();
console.log('Game server running...');
app.use(express.bodyParser())
console.log('Player submitted high-score:');
app.get('/', function(req, res) {
var score = req.body.score;
console.log(score);
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('_testcb(\'"Your high-score has been submitted."\')');
});
app.listen(80);
req is the request, containing data from the current request, and res is the response you send back from the server, so trying to get the data from the input from the respone you send back is not going to work.

Categories