Can't get one node.js server to talk to another - node.js

I have two node servers, one on port 5000 (call it "Face") and another on port 5001 (call it "Hands")
Both are started via a foreman procfile at the same time. Ports are fixed and the url I'm targeting works in the browser.
When the Hands starts up, it needs to talk to the Face (Facepalm?) and register itself. However, the below code doesn't seem to be working. (This is coffeescript generated JS)
Register gets called during server initialization, after the http server has been started. In case it was a timing issue, I kick off the register function with a setTimeout() of 2 seconds. I know the page that its hitting (/home/register) is available and working.
Right now I can see it get to the "Posting to" console log line. On the Face I have put a console.log in the register code and its never logging anything - meaning I don't think its actually getting hit. (It DOES log if hit from browser) And nothing errors out - it just calls the request and then wanders off to get a sandwich.
Both servers are "roll your own" - not using any frameworks. Let me know if you see a weird typo or need more info. Thanks!
register = function() {
var _this = this;
console.log('Registering with Face Server');
return post_face('/home/register', GLOBAL.data, function(rs) {
console.log(rs);
if (rs.registered) {
GLOBAL.data.registered = true;
return console.log("Registered with face at " + GLOBAL.config.face_host + ":" + GLOBAL.config.face_port);
} else {
throw "ERROR: Could not register with face server! " + GLOBAL.config.face_host + ":" + GLOBAL.config.face_port;
return false;
}
});
};
post_face = function(path, data, cb) {
var post_data, post_options, post_req;
post_data = querystring.stringify({
'registration': data
});
post_options = {
host: GLOBAL.config.face_host,
port: GLOBAL.config.face_port,
path: path,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': post_data.length
}
};
console.log("Posting to " + post_options.host + ":" + post_options.port);
post_req = http.request(post_options, function(res) {
var response,
_this = this;
console.log(res);
response = "";
res.setEncoding('utf8');
res.on('data', function(chunk) {
return response += chunk;
});
return res.on('end', function() {
return cb.call(_this, response);
});
});
return true;
};

Thanks to Bill above, the answer was that I wasn't actually posting the data and ending the request! Bad copy / paste / edit from some samples I was referring to. Here's the last two lines of code I should have had:
post_req.write(post_data);
post_req.end();

Related

Node request fails with socket hang up

I have a consistent problem with using the request module where, regardless of the URL I provide, I am getting a socket hang up error, generally a connection reset. What makes this more strange is that this code works on another developers machine without problem.
var request = require("request");
request("http://google.com", function(error, response, body) {
console.log(error);
console.log(response);
if (!error && response.statusCode === 200) {
}
});
This is a simplified version of the code but it illustrates the point. If I do something like this though
var http = require('http');
var options = {
host: 'www.google.com',
port: 80
};
http.get(options, function (resp) {
var bdy = "";
resp.on('data', function (chunk) {
bdy = bdy + chunk;
});
resp.on('end', function () {
//var r = JSON.parse(bdy);
console.log(bdy);
});
}).on("error", function (e) {
console.log("Got error: " + e.message);
});
I get a response back from Google as I would expect. What is strange is that both the request module and another module I am using (weather-js) exhibiting the same behavior: all requests result in some sort of socket error. Additionally, when I run Fiddler I can see the http.get request go out, but I never see an entry when the code from the request or weather-js module runs.
I am running Node 10.5.0 on Windows 10.

How do I http.get localhost

I am trying to fetch a page from port 1717 but when my bandwidth is unavailable, the http.get on error callback logs errno ENOENT whereas when I turn my bandwidth back on, it logs errno ECONNRESET. Regardless of my computer being offline or not, the url http://localhost:1717/admin/available/ ALWAYS returns content in the browser as long as the server is up and running. I've tried using postman and I have also tried using request method of the http module instead of get. I ended request after using it but I still got the same errors.
Meanwhile I have tried getting other links besides those on localhost and it fetched them. In some other threads, I saw people suggest I use hostname 127.0.0.1 instead of localhost. That too did not work so I switched to the request module from npm then there was a slight difference in behavior. In the server.js, I have sommething like this for GET requests hitting /admin/available/
console.log('giving you table', table)
res.writeHead(200, {"Content-Type": "text/html"});
res.end(table);
However, when I use the request module, it throws the error ECONNRESET but in the CLI window where the server is running, this console.log('giving you table', table) is logged, meaning the server does see that request but somehow, the module still throws ECONNRESET and the body and response variables are undefined, claiming it cannot see it. What can I do about this?
I'll be posting my code below in case I'm missing something.
var http = require('http'),
component = require('../lib/render-component'),
render = {username: '', available: '', orders: '', frequent: ''};
// for simplicity
var request = require('request');
request('http://localhost:1717/admin/available', function(err, res, body) {
console.log(err, res, body)
});
// intended use scenario
http.get({port: 1717, path: '/admin/available/', headers: {Accept: 'text/html'}}, function(res) {
var temp = '';
res.setEncoding('utf8');
console.log('inside get');
res.on('data', function (chunk) {
temp += chunk;
}).on('end', function() {
render.available = temp;
http.get('http://localhost:1717/admin/order/?page=0', function(res) {
var temp = ''
res.setEncoding('utf8');
res.on('data', function (chunk) {
temp += chunk;
}).on('end', function() {
render.orders = temp;
ordersModel.find({status: 'delivered'}, 'food', function (err, orders) {
if (err) throw err;
var hashMap = [], returnArr = [];
orders.forEach(function (order) {
hashMap.push(order.toObject()['food'].split(","));
})
hashMap.reduce(function(a, b) {
return a.concat(b)
}, []).forEach(function(item) {
if ((k = returnArr.findIndex(function(elem) {
return elem[0] == item;
})) != -1) {
returnArr[k][1]++;
}
else returnArr.push([item, 1]);
})
// filter the ones with the highest value
hashMap = [], returnArr = returnArr.sort(function(a, b) {
return b[1] - a[1];
}).slice(0, 5).forEach(function(elem) {
hashMap.push({name: elem[0], counter: elem[1]})
});
render.frequent = component("frequent", hashMap);
console.log(render)
}) // orders model find
}); // get orders
}).on('error', function(e) {
console.log(e)
});
}); // available on end
}).on('error', function(e) {
console.log('err available', e)
}); // available on error
Please help me. I've been stuck for three days now.

Wait for JSON response data from POST request in nodejs (mocha test)

I'm aware that there are several questions related to mine, but I didn't find any of them useful:
this one doesn't apply to my case, I'm actually getting the answer, it's the contents that I can't get.
on this one, on the other hand, the problem is a wrong handling of an asynchronous call, which is not my case
there, well, I really didn't fully understand this question
And so on...
Then, I think this is a legitimate question. I'm actually performing some encryption in my server (express routing in node) through a post request:
app.post('/encrypt', encrypt);
Encrypt is doing:
function encrypt(req,res) {
if(req.body.key && req.body.message) {
var encryptedMessage = Encrypter.encrypt(req.body.key,req.body.message);
return res.status(200).json({ message: encryptedMessage });
}
res.status(409).json({ message: 'the message could not be encrypted, no key found' });
}
}
So, I tested this via console.log, and it's working. When the server receives the request, the encrypted message is being generated.
At the same time, I'm testing my thing with mocha and I'm doing it like so:
describe('# Here is where the fun starts ', function () {
/**
* Start and stop the server
*/
before(function () {
server.listen(port);
});
after(function () {
server.close();
});
it('Requesting an encrypted message', function(done) {
var postData = querystring.stringify({
key : key,
message : message
});
var options = {
hostname: hostname,
port: port,
path: '/encrypt',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': postData.length
}
};
var req = http.request(options, function(res) {
res.statusCode.should.equal(200);
var encryptedMessage = res.message;
encryptedMessage.should.not.equal(message);
done();
});
req.on('error', function(e) {
//I'm aware should.fail doesn't work like this
should.fail('problem with request: ' + e.message);
});
req.write(postData);
req.end();
});
});
So, whenever I execute the tests, it fails with Uncaught TypeError: Cannot read property 'should' of undefined because res.message does not exist.
None of the res.on (data, end, events is working, so I suppose the data should be available from there. First I had this:
var req = http.request(options, function(res) {
res.statusCode.should.equal(200);
var encryptedMessage;
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
encryptedMessage = chunk.message;
});
encryptedMessage.should.not.equal(message);
done();
});
But res.on was never accessed (the console.log didn't show anything). I'm therefore a bit stuck here. I'm surely doing some basic stuff wrong, but I don't have a clue, and the many questions I found doesn't seem to apply to my case.
Weird enough, if I launch a test server and then I curl it
curl --data "key=secret&message=veryimportantstuffiabsolutellyneedtoprotect" localhost:2409/encrypt
Curl justs waits ad aeternam.
Actually I was doing it properly at the beginning, and the problem was indeed the same than in the second question I mentionned I was actually "clearing" my context with done() before the post data arrived. The solution is:
var req = http.request(options, function(res) {
res.statusCode.should.equal(200);
res.on('data', function(data) {
encryptedMessage = JSON.parse(data).message;
encryptedMessage.should.not.equal(message);
done();
});
});
In such a way that done() is only called when the data has been threated. Otherwise, mocha will not wait for the answer.

nodejs/express - stream stdout instantly to the client

I spawned the following child: var spw = spawn('ping', ['-n','10', '127.0.0.1']) and I would like to receive the ping results on the client side (browser) one by one, not as a whole.
So far I tried this:
app.get('/path', function(req, res) {
...
spw.stdout.on('data', function (data) {
var str = data.toString();
res.write(str + "\n");
});
...
}
and that:
...
spw.stdout.pipe(res);
...
In both cases browser waits 10 of the pings to complete, and then prints the result as a whole. I would like to have them one by one, how to accomplish that?
(Client is just making a call to .../path and console.logs the result)
EDIT: Although I do believe that websockets are necessary to implement this, I just want to know whether there are any other ways. I saw several confusing SO answers, and blog posts (in this post, at step one OP streams the logs to the browser) which didn't help, therefore I decided to go for a bounty for some attention.
Here's a complete example using SSE (Server sent events). This works in Firefox and probably Chrome too:
var cp = require("child_process"),
express = require("express"),
app = express();
app.configure(function(){
app.use(express.static(__dirname));
});
app.get('/msg', function(req, res){
res.writeHead(200, { "Content-Type": "text/event-stream",
"Cache-control": "no-cache" });
var spw = cp.spawn('ping', ['-c', '100', '127.0.0.1']),
str = "";
spw.stdout.on('data', function (data) {
str += data.toString();
// just so we can see the server is doing something
console.log("data");
// Flush out line by line.
var lines = str.split("\n");
for(var i in lines) {
if(i == lines.length - 1) {
str = lines[i];
} else{
// Note: The double-newline is *required*
res.write('data: ' + lines[i] + "\n\n");
}
}
});
spw.on('close', function (code) {
res.end(str);
});
spw.stderr.on('data', function (data) {
res.end('stderr: ' + data);
});
});
app.listen(4000);
And the client HTML:
<!DOCTYPE Html>
<html>
<body>
<ul id="eventlist"> </ul>
<script>
var eventList = document.getElementById("eventlist");
var evtSource = new EventSource("http://localhost:4000/msg");
var newElement = document.createElement("li");
newElement.innerHTML = "Messages:";
eventList.appendChild(newElement);
evtSource.onmessage = function(e) {
console.log("received event");
console.log(e);
var newElement = document.createElement("li");
newElement.innerHTML = "message: " + e.data;
eventList.appendChild(newElement);
};
evtSource.onerror = function(e) {
console.log("EventSource failed.");
};
console.log(evtSource);
</script>
</body>
</html>
Run node index.js and point your browser at http://localhost:4000/client.html.
Note that I had to use the "-c" option rather than "-n" since I'm running OS X.
If you are using Google Chrome, changing the content-type to "text/event-stream" does what your looking for.
res.writeHead(200, { "Content-Type": "text/event-stream" });
See my gist for complete example: https://gist.github.com/sfarthin/9139500
This cannot be achieved with the standard HTTP request/response cycle. Basically what you are trying to do is make a "push" or "realtime" server. This can only be achieved with xhr-polling or websockets.
Code Example 1:
app.get('/path', function(req, res) {
...
spw.stdout.on('data', function (data) {
var str = data.toString();
res.write(str + "\n");
});
...
}
This code never sends an end signal and therefore will never respond. If you were to add a call to res.end() within that event handler, you will only get the first ping – which is the expected behavior because you are ending the response stream after the first chunk of data from stdout.
Code Sample 2:
spw.stdout.pipe(res);
Here stdout is flushing the packets to the browser, but the browser will not render the data chunks until all packets are received. Thus the reason why it waits 10 seconds and then renders the entirety of stdout. The major benefit to this method is not buffering the response in memory before sending — keeping your memory footprint lightweight.

Sending contents of var within http.request area through socket

I have a program written with node that connects to Flash. In Flash when a key is pressed the keypress is sent through a socket to node, which then echoes the keypress back to Flash with some extra text. The Flash part works fine. The node portion basically works, except for one part where I connect to a web page. What I want to do is get the contents of a web page and echo that back to Flash though a socket. Here's my code:
var net = require('net');
var http = require('http'),
sys = require('sys'),
fs = require('fs');
var options = {
host: 'theurl.com',
port: 80,
path: '/',
method: 'POST'
};
var msg;
var mySocket;
var server = net.createServer(function(socket) {
mySocket = socket;
mySocket.on("connect", onConnect);
mySocket.on("data", onData);
});
function onConnect() {
console.log("Connected to Flash");
}
function onData(d) {
if(d == "exit\0") {
console.log("exit");
mySocket.end();
server.close();
} else if(d == "32\0") {
var req = http.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
msg = chunk;
console.log("in function: msg = " + msg);
mySocket.write(msg, 'utf8');
});
});
console.log("right after res: msg = " + msg);
mySocket.write("right after res: "+msg, 'utf8');
// write data to request body
req.write('data\n');
req.write('data\n');
req.end();
mySocket.write("32 part: " + d, 'utf8');
} else {
console.log("From Flash = " + d );
mySocket.write(d, 'utf8');
}
}
server.listen(8080, "192.168.0.1");
When I press spacebar (no 32) the data seems to be written but doesn't show up on the Flash side until I press 2 keys. Note that the part outside of the "http.request" area DOES show up on the Flash side correctly. So the mysocket.write within the res.on area doesn't show up until 2 keypresses, but the mysocket.write that says "right after res" shows up just like I want it to. SO I figure that I need one of these things to happen:
1) The chunk returned from the http.request area be visible outside of that area
2) the mysocket.write within the http.request area to work the same way as the mysocket.write outside of the http.request area
3) store the chunk to the hard drive and then reread the contents stored later and send that
Those are the options I've thought of. I think #3 makes no sense since I seem to have the var in the program, but just can't access it where I want to. Not sure about why the socket doesn't write the same within that area as it does outside of that area, but if there were a way to do #1 that seems to me to make the most sense. I am open to suggestions though. Thanks for your time.
Darryl

Resources