I'm planning to use nodeJS as my comet server and I wrote some code for testing, but there is an issue that when client connected to the server for the first time, it couldn't get response from server.
Here is the server-side code (server.js):
var util = require('util');
var redis = require('redis').createClient(6379, '192.168.1.254');
var http = require('http');
redis.on("error", function (err) {
console.log("Error " + err);
});
var server = http.createServer(requestListener);
server.listen(9898, '192.168.1.254');
function requestListener(req, res) {
util.log('Connected.');
redis.brpoplpush('msg:q:1', 'msg:s:1', 20, function(err, reply) {
if (err) {
util.log('ERROR: ' + err);
}
var length = reply ? reply.length : 0;
res.writeHead(200, {
'Content-Type':'text/plain',
'Content-Length':length
});
if (length) {
res.end(reply);
util.log('Sent: ' + reply);
} else {
res.end('');
}
});
}
And the client code (client.sh):
#!/bin/bash
while [ 1 ]
do
curl -i http://192.168.1.254:9898
done
I tested it following steps:
node server.js
./client.sh
In redis, LPUSH('msg:q:1', 'blablah')
Now, "Sent: blablah" printed on console, res.end(reply) excuted, but client receives nothing. I repeat step 3 for many times, then it works as expect. If I restart the client, the first few responses can't be received again.
How can I resolve this?
I think what might happening here is you've aborted curl while it was waiting for the response from redis. After the HTTP client is aborted, the redis command still stays active. You then push another element onto the queue, the redis command returns, but has no HTTP response to write it to. When you start the curl loop again, you find the queue empty.
Here's a modified version of your program that streams the response and detects a client abort. It doesn't put the element back on the queue, but you could certainly do that as well.
var util = require('util');
var redis = require('redis').createClient();
var http = require('http');
redis.on("error", function (err) {
console.log("Redis error " + err);
});
redis.on("ready", function () {
console.log("Redis client ready");
});
var server = http.createServer(requestListener);
server.listen(9898);
function requestListener(req, res) {
var aborted = false;
res.writeHead(200, {
"Content-Type": "text/plain"
});
res.write("Checking redis...\n");
redis.brpoplpush('q', 's', 20, function (err, reply) {
if (aborted) {
return console.log("Client aborted before redis reply came back.");
}
if (err) {
return res.end("Redis error");
}
res.end("Redis reply: " + reply);
});
req.on("aborted", function () {
console.log("HTTP client aborted.");
aborted = true;
});
}
Related
I've started a project that requires communication between an arduino and a local nodejs server (unrelated the data will be sent via an http request or a socket to the actual remote server later on). I'm using the node package serialport. At the beginning of the serial communication, the server needs to "find" the arduino. I've decided on the following negotiation codex:
1) the server sends a "c" character (as in connect) which the arduino is listening for
2) the arduino replies to all "c"s with another "c" which the server will be listening for
in other words when both sides receive a "c" that means the serial connection works
However, due to serialport using promises I can't go through all available ports and check if there's an arduino (which replies with "c") there.
Here's what I've come up with so far:
var SerialPort = require('serialport');
var Readline = require('#serialport/parser-readline');
async function tryPort(path) {
var port = new SerialPort(path, {
baudRate: 9600
});
port.on('error', function (err) {
console.log(err);
});
port.pipe(new Readline({ delimiter: '\n' })).on('data', (data)=>{
console.log(port);
console.log(data);
if (data == 'c') {
return port;
}
port.close();
});
port.write("c", function (err) {
if (err) console.log(err);
});
}
async function connect() {
var connection, ports = await SerialPort.list();
for(i=0;i<ports.length;i++){
connection = await tryPort(ports[i].path);
}
setTimeout(() => {
if (!connection) {
console.log("no port/response found");
}else{
console.log(connection);
}
}, 3000);
}
connect();
I went with the assumption the variable 'connection' will be assigned the value of the port that responded correctly last because that port will take the longest to finish. Unfortunately, it seems this won't work with promises... So I'm wondering if there's any other way to accomplish it?
I'm using express,socketio and socketio-client in my application.
(I not very comfortable with nodejs stack...)
to summarize my application flow :
Client => node/express API + Socketoi server <=> nodejs (Socketio-client)
browser send request to a nodejs/express (route /api)
Do some request headers overwrites with middlewares
In the route '/', server sends an emit to a nodejs (Socketio-client)
after executing some logic, socketio-client emit an event with the logics result
I need this result to be send in the response to the client
My code below:
router.get('/*', function (req, res) {
//emit data for socketio-client to apply some logic
app.io.sockets.emit('req', {
reqheader : req.headers,
requrl : req.protocol + "://" + req.headers.host + req.url,
reqmethod : req.method
});
console.log("after emit");
//I use callback to make response wait for socketio server to catch event from client
waitforevent(req, res, function (__res) {
console.log("callback" );
res.end(__res.body);
res.sendStatus(__res.statusCode);
//res.end();
});
function waitforevent(req, res, callback) {
console.log("waiting for event" );
app.io.__socket.on('respp', function (data) {
//console.log("no response yet \n" + JSON.parse(data) );
__res = JSON.parse(data);
console.log("event catched...");
callback(__res);
});
}
});
My problem :
This works only the first time I send a Get http://localhost:3000/api frome the browser. __res.body is printed in the browser.
req 1
after emit
waiting for event
event catched...
callback
Error: Can't set headers after they are sent.
**GET /api 200 73.841 ms - -**
req 2
after emit
waiting for event
Next request will just wait for server to respond, which is, I suspect, not happening because the app.io.__socket.on('respp', function (data){...} is never catched by the server.
After sending more request (while the others are waiting), I noticed this warning in server logs:
(node) warning: possible EventEmitter memory leak detected. 11 respp listeners added. Use emitter.setMaxListeners() to increase limit.
Is there other ways to catch events in a route before sending response to clients?
I solved with once:
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var socket;
io.on('connection', function (sock) {
console.log('Connected');
socket = sock;
});
server.listen(3000);
app.get('/*', function (req, res) {
socket.once('event', function (data) {
if (data.error) {
console.log('is an error');
res.status(400).json(data);
} else {
console.log('is ok');
res.status(200).json(data);
}
});
io.emit('ask-for-event', { data: data });
});
You could remove the event listener when the socket closes to avoid the event listener leak:
router.get('/*', function (req, res) {
app.io.sockets.emit('req', {
reqheader : req.headers,
requrl : req.protocol + "://" + req.headers.host + req.url,
reqmethod : req.method
});
req.socket.on('close', function() {
app.io.__socket.removeListener('respp', resppHandler);
});
app.io.__socket.on('respp', resppHandler);
function resppHandler(data) {
data = JSON.parse(data);
res.statusCode = data.statusCode;
res.end(data.body);
}
});
I'm not sure if app.io.__socket should really be app.io.sockets or not, but I copied it as-is from your code, assuming you know what you're doing.
Additionally, you may wish to add some sort of timeout so as not to keep the request waiting indefinitely.
I'd like to use node.js to query a mySQL-database and return the results as JSON to be used in a mobile application. Unfortunately, my request just sorta times out and the server does nothing for a good 2 minutes until the log-files show my console.log()-statements.
Also, the callback doesn't return anything as result. It's just empty.
// Check dependencies
var http = require('http');
// Create the http server.
// reference: http://net.tutsplus.com/tutorials/javascript-ajax/node-js-for-beginners/
http.createServer(function(request, response) {
// Attach listener on end event.
request.on('close', function() {
console.log('request');
// run asynchronous
getSQL(function(err, result) {
console.log('json:', result);
response.writeHead(200, {
'Content-Type' : 'x-application/json'
});
// Send data as JSON string.
response.end(result);
});
});
}).listen(3000);
// Access MySQL via node-mysql
// https://github.com/felixge/node-mysql
function getSQL(callback) {
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'user',
password : 'pw',
database : 'db',
socketPath : '/var/run/mysqld/mysqld.sock', // socket for communication from debian <-> client, seems not to be set correcly by default?
});
connection.connect();
var json = '';
var query = 'SELECT * FROM test';
connection.query(query, function(err, results, fields) {
if (err)
return callback(err, null);
console.log('The result is: ', results[0]);
// wrap result-set as json
json = JSON.stringify(results);
});
connection.end();
callback(null, json);
};
Output after like 2 minutes:
$ node app.js
request
json:
The result is: { test: 'avc' }
json2: [{"test":"avc"}]
Based on my very basic understanding of the whole node.js-concept, my code should query the db (it does) and return a json once it's finished via the callback-function (apparently doesn't) which than is sent back as a response to the client (can't really check that since the json's empty).
I guess I made one (or a couple) major mistakes. Help and/or helpful links would be much appreciated. Thanks!
Solution, thanks to hexacyanide
// Check dependencies
var http = require('http');
// Create the http server.
// reference: http://net.tutsplus.com/tutorials/javascript-ajax/node-js-for-beginners/
/***************
* Correction 1: Using the request.on('close', function()( ... )-listener isn't required anymore
***************/
http.createServer(function(req, res) {
console.log('Receving request...');
var callback = function(err, result) {
res.writeHead(200, {
'Content-Type' : 'x-application/json'
});
console.log('json:', result);
res.end(result);
};
getSQL(callback);
}).listen(3000);
// Access MySQL via node-mysql
// https://github.com/felixge/node-mysql
function getSQL(callback) {
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'user',
password : 'pw',
database : 'db',
socketPath : '/var/run/mysqld/mysqld.sock', // socket for communication from debian <-> client, seems not to be set correcly by default?
});
connection.connect();
var json = '';
var query = 'SELECT * FROM test';
connection.query(query, function(err, results, fields) {
if (err)
return callback(err, null);
console.log('The query-result is: ', results[0]);
// wrap result-set as json
json = JSON.stringify(results);
/***************
* Correction 2: Nest the callback correctly!
***************/
connection.end();
console.log('JSON-result:', json);
callback(null, json);
});
};
You're following an older guide which instructs you to wait for the request's close event before sending the response, but you actually no longer need to do that.
What's happening is you aren't sending your response, so your client is timing out. Only until the client times out is when close events fires. Since the client has disconnected by the time you send your response, you don't get anything on the client and only see it in the terminal.
To fix this problem, just stop waiting for the close event and run code immediately when the request handler is called:
var http = require('http');
http.createServer(function(req, res) {
getSQL(function(err, result) {
res.writeHead(200, {
'Content-Type' : 'x-application/json'
});
res.end(result);
});
}).listen(3000);
I am attempting to test drive an node.js application based on express. I want to return a simple 404.html, which I can successfully do, but afterward, calling close on the node http server gets this error:
Fatal error: Cannot call method 'call' of undefined
I am having a hard time tracking down what is undefined because the same method works beautifully when called elsewhere.
Here is my express code:
function Server() {
this.port = 9000;
this.staticDir = '/public';
}
function handleHomeRequest(req, res) {
var body = '<html><body>Home Page.</body></html>';
res.send(body);
}
Server.prototype.start = function () {
expServer = express();
expServer.get('/', function (req, res) { handleHomeRequest(req, res); });
expServer.use(function (req, res) {
res.status(404).sendfile('./src/public/404.html');
});
runningServer = expServer.listen(this.port);
};
Server.prototype.stop = function (cb) {
runningServer.close(cb);
};
Here is my nodeunit test code:
var ROOT_URL = 'http://localhost',
PORT = 9000,
URL = ROOT_URL + ':' + PORT + '/',
http = require('http'),
Server = require('./server.js'),
server;
exports.setUp = function(done) {
server = new Server();
done();
};
exports.tearDown = function (done) {
server = null;
done();
};
exports['Requesting a page that does not exist results in a 404.'] = function (test) {
server.start();
httpGet(URL + 'guaranteedNotToExistPage', function(res, data) {
test.equal(404, res.statusCode, 'Requesting a page that dne did not return with a status code of 404.');
test.ok(data.indexOf('404 Page Not Found') > -1, 'The 404 page was not returned.');
//test.done();
server.stop(test.done);
});
};
function httpGet(url, callback) {
var request = http.get(url),
receivedData = '';
request.on('response', function (response) {
response.setEncoding('utf8');
response.on('data', function (chunk) {
receivedData += chunk;
});
response.on('end', function () {
callback(response, receivedData);
});
});
}
The result of the http get request come back, the failure only occurs when I call server.stop(test.done); however, stopping the server is required to ensure my unit tests can be run in any order and independent.
First, where runningServer is defined? I can't see a
var runningServer;
anywhere in the first peace of code.
So, if you write a value in prototype.start I doubt you can access it on prototype.stop that is a different scope.
Second, {expressListener}.close() in node 0.6 was just synchronous, they added the callback on the 0.8. So, check the node.js version to be sure that the {cb} is correctly handled.
I am trying to connect to a MS SQL Server DB using node.js. I installed the msnodesql module to use for this task. I am able to connect to a DB with the following code:
var sql = require('msnodesql');
var util = require('util');
//
var connStr = "Driver={SQL Server Native Client 11.0};Server=myySqlDb,1433;Database=DB;UID=Henry;PWD=cat;";
var query = "SELECT * FROM GAData WHERE TestID = 17";
sql.open(connStr, function(err,conn){
if(err){
return console.error("Could not connect to sql: ", err);
}
conn.query(query,function(err,results){
if (err){
return console.error("Error running query: ", err);
}
console.log(results);
console.log(results.length);
for (var i = 0; i <= results.length; i++){
util.inspect(results[i]);
}
});
});
My goal however is to connect to the DB from various events, such as button submits, from a HTML page. From the button click I want to call a node.js function to query the DB for a particular attribute, such as the following:
From the HTML:
<br /><button type="submit" id="continue" onClick="verifyEmail($('#email').val())">Continue</button>
From the script file:
function verifyEmail(email){
var mQuery = "'EXEC WebUserRecovery '" + email + "'";
sql.open(conn_str, function (err, conn) {
if (err) {
console.log("Error opening the connection!\r\n" + err);
return;
}
connection.query(mQuery,function(err,results){
if (err){
return console.error("Error running query: ", err);
}
alert(results);
});
});
}
The code when put inside the function does not work, a DB connection is unsuccessful. Can anyone advise how to fix this issue? There is little good documentation on msnodesql out there...
Server side .js file (Node.js):
var sql = require('msnodesql');
var util = require('util');
var connStr = "Driver={SQL Server Native Client 11.0};Server=myySqlDb,1433;Database=DB;UID=Henry;PWD=cat;";
var query = "SELECT * FROM GAData WHERE TestID = 17";
// Load the http module to create an http server.
var http = require('http');
// Configure our HTTP server to respond with Hello World to all requests.
var server = http.createServer(function (request, response) {
sql.open(connStr, function(err,conn){
if(err){
return console.error("Could not connect to sql: ", err);
}
conn.query(query,function(err,results){
if (err){
return console.error("Error running query: ", err);
}
response.writeHead(200, {"Content-Length": results.length});
response.writeHead(200, {"Content-Type": "application/json"});
response.end(results);
});
});
});
// Listen on port 8000, IP defaults to 127.0.0.1
server.listen(8000);
// Put a friendly message on the terminal
console.log("Server running at http://127.0.0.1:8000/");
At Client Side .js file or in-line script should be something like following using jQuery ajax call:
var request = $.ajax({
url: "http://127.0.0.1:8000/",
type: "GET",
dataType: "json"
});
request.done(function(dataRcvd) {
alert(JSON.stringify(dataRcvd));
});