How to receive ZMQ message inside Express middleware? - node.js

I want to send ZMQ message inside app.get but when running I throw error:
events.js:72
throw er; // Unhandled 'error' event
^
ReferenceError: res is not defined
My running code:
var zmq = require('zmq'),
zreq = zmq.socket('req'),
app = express();
zreq.connect('tcp://localhost:5559');
zreq.on('message', function (msg) {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.send(msg);
});
app.get('/words', function (req, res) {
zreq.send('nodejs');
//I think it should have something like zreqCallback(req)?
});

The problem is, as the error indicates, that you don't have access to the res object from the message event handler on your req socket. What you need is a way to link the message in that event handler to your res object. You're not going to be able to do that (easily) without support from the other end of that socket.
The basic idea is to associate a unique id with each message you send over zmq and include it in the message sent through the req socket and the reply that comes back from the rep socket. Then also associate the res object with the same message id.
I usually use node-uuid for unique id generation. You'll also need a way to easily encode / decode your messages (it looks like you're just sending straight strings at the moment). The built in JSON parser works fine for that, or you could use something more compact like bencode or protobuf. Be sure to pick something that both ends of the socket can work with.
You're code would look something like this:
Note: I'm assuming we're using node-uuid and JSON. Also, I'm not putting any error handling or sanity checks in here; don't forget that stuff.
var zmq = require('zmq'),
uuid = require('node-uuid'),
zreq = zmq.socket('req'),
app = express();
var responses = {};
zreq.connect('tcp://localhost:5559');
zreq.on('message', function (data) {
data = JSON.parse(data);
var msgId = data.id;
var res = responses[msgId];
res.writeHead(200, { 'Content-Type': 'application/json' });
res.send(data.message);
responses[msgId] = null;
});
app.get('/words', function (req, res) {
var msgId = uuid.v4();
var data = { id: msgId, message: 'nodejs' };
responses[msgId] = res;
zreq.send(JSON.stringify(data));
});
On the other end (I'll just assume it's also written in node for the purpose of this example):
var zmq = require('zmq');
zrep = zmq.socket('rep');
zrep.bind('tcp://localhost:5559');
zrep.on('message', function(data) {
data = JSON.parse(data);
var msgId = data.id;
var msg = data.message;
// Do whatever you were doing before to process the message
// We'll say it ends up in a "results" variable
var response = { id: msgId, message: results };
zrep.send(JSON.stringify(response));
});

Related

node-soap -- how to capture soap request before it is handled by soap listener

I created a soap server in nodejs using the node-soap module. But I get an error indicating there is some problem in the incoming soap xml (listed below).
< soap log: { Fault: < { faultcode: 500, < faultstring:
'Invalid XML', < detail: 'Error: Non-whitespace before first
tag.\nLine: 1\nColumn: 1\nChar: -', < statusCode: undefined } }
When I searched around in google, it indicated that it is the problem of BOM (Byte Order Mark) which the windows OS inserts into the unicode buffer. Most of the solutions suggested to replace/remove this BOM before calling the xml parser.
Now, when I am using node-soap module, I am unable to figure out where to apply this fix, below being my server code.
/**
* Simple demonstration of soap service
**/
var soapService = require("./rv.js");
var xml = require('fs').readFileSync('./mmsxmlpushservicews.wsdl.xml', 'utf8');
var express = require('express');
var bodyParser = require('body-parser');
var soap = require('soap');
var app = express();
app.use(bodyParser.raw({type: function() { return true; }, limit: '5mb' }));
app.listen(8001, function(err) {
if (err) {
console.error("error:", err);
process.exit(1);
}
var server = soap.listen(app, '/smshttp/soapws', soapService, xml);
server.log = function(type, data) {
//console.log("soap log:", data);
}
console.log("service running on port 8001...");
});
In the above soap server code, is there an event / callback hook that I can make use of to modify the soap request buffer, before the soap server performs its parsing?
If yes, where and how should I be doing it?
Add this to your code after this line 'app.use(bodyParser.raw({type: function() { return true; }, limit: '5mb' }));'
app.use(function(req, res, next) {
var body = req.body.toString();
var body = body.replace('\ufeff', '');
req.body = Buffer.from(body);
next();
});
This hook in express allows you process every request, evaluate which urls have been called and safely forward to the next listener with 'next()'.
But consider that this function will be called for EVERY request, so don't forget to filter only those, where you do need to clean the string.

How to use socket event from another function?

In socket.io we create a instance and use socket like this
var server = require('http').createServer();
var io = require('socket.io')(server);
io.on('connection', function(socket){
socket.on('event', function(data){});
socket.on('disconnect', function(){});
});
server.listen(3000);
How we can create a socket event in other function like this. Is there any way or trick to this properly.
var server = require('http').createServer();
var io = require('socket.io')(server);
io.on('connection', function(socket){
socket.on('event', function(data){});
socket.on('disconnect', function(){});
});
var f1 = function (socketID) {
if(socketID){
io.to(socketID).emit('event1', 'event1 data'); //working
socket.on('call2', function (data) { // not working
});
}
}
server.listen(3000);
When you are sending a request and trying to wait for a specific response to that request, it is bit tricky to use a message-based protocol like socket.io for that situation. HTTP is perfectly designed for request/response since a single connection is used only for that one request/response and therefore the response is the response that belongs to your request.
This is not true with socket.io. It's a message based scheme. When you send a message and then wait for a message back from the other end (in a multi-user environment), you have to be very careful that you don't:
Install too many event listeners and end up with duplicates.
That the response you're getting is specifically for your original request and not for some other request that might be happening in a similar time frame.
One way to solve this issue is to add a request identifier to all your request/response messages. When you send the request, you add a unique request ID. When the response is returned, it includes that request ID and then your code can tell which response belongs with which request.
Here's an idea for how to implement the request ID concept (this needs the other end to cooperate and return the same request ID that it was sent):
var idCntr = 0;
function f1(socketID) {
if(socketID){
var id = idCntr++;
io.to(socketID).emit('event1', {id: id, data: 'event data'});
function listener(data) {
// if this is our message
if (data.id === id) {
// once our response is received, remove event handler
socket.removeListener('responseToEvent1', listener);
// process response here
// code here...
}
}
// wait for our response
socket.on('responseToEvent1', listener);
}
}
Or, here's a more object oriented scheme that adds a method to the socket object called .emitRequest():
var idCntr = 0;
socket.emitRequest = function(msg, data, responseMsg, responseFn) {
var id = idCntr++;
function listener(response) {
// if this is our message
if (response.id === id) {
// once our response is received, remove event handler
this.removeListener(responseMsg, listener);
// call response handler
responseFn(response.data);
}
}
this.emit(msg, {id: id, data: data});
this.on(responseMsg, listener);
}
Note: With both of these pieces of code, the other end of your connection needs to cooperate and return the id property of the original request so that the receiving listener can tell which response goes with which request.

Correct way to respond to client on Node.js?

This being my first attempt at building a server...
I have set up a server to handle a contact form submission that also includes a predefined captcha string.
When the server receives the contact form, if the captcha string is the one expected then I want it to simply respond with a JSON of the parsed contact form query using response.end(JSON.stringify(parsedURL));
If the captcha string is wrong, I want the server to respond "saying" the captcha was wrong, so that the client asks the user to try again. But I don't know how to do that.
ON THE SERVER :
var httpServer = http.createServer(function (request, response)
{
if (/\/contactform\?....../.test(request.url))
{
var parsedURL = url.parse(request.url, true);
var name = parsedURL.query.name;
var email = parsedURL.query.email;
var subject = parsedURL.query.subject;
var enquiry = parsedURL.query.enquiry;
var captcha = parsedURL.query.captcha;
if (captcha !== "testing")
{
// send a "bad" response to the client and include the message "bad captcha"
}
else response.end(JSON.stringify(parsedURL.query));
}
}).listen(8080);
ON THE CLIENT :
$.ajax({
url: "/contactform?..............",
success: function(msg)
{
console.log(msg);
},
error: function(msg)
{
// the "bad captcha" response should be handled here right ?
console.log(msg); // which should be equivalent to console.log("bad captcha");
}
});
When I use response.end(JSON.stringify(parsedURL)); the client (jQuery) considers that a "success".
How should I respond from the server so that the "error" part of the ajax request on the client is executed?
Or is the "error" part supposed to handle only cases where the server doesn't respond at all, i.e. when something has gone horribly wrong server-side, like an exception, a real error, and not cases where simply my evaluation on the server doesn't have the expected outcome ?
Should I instead useresponse.end(...); in both cases as in :
ON THE SERVER :
var httpServer = http.createServer(function (request, response)
{
if (/\/contactform\?....../.test(request.url))
{
var parsedURL = url.parse(request.url, true);
var name = parsedURL.query.name;
var email = parsedURL.query.email;
var subject = parsedURL.query.subject;
var enquiry = parsedURL.query.enquiry;
var captcha = parsedURL.query.captcha;
var response = JSON.stringify(parsedURL.query);
if (captcha !== "testing") response = "bad captcha";
response.end(response);
}
}).listen(8080);
ON THE CLIENT :
$.ajax({
url: "/contactform?..............",
success: function(msg)
{
console.log(msg); // msg will either be the stringified object or "bad captcha"..
}
});
In other words, when a request is successfully received on the server but the server wants to let the client know that something was missing or whatever, should the response from the server be sent as an "error" (i.e. handled by the "error" block on the client's ajax code) or as a "success" with the appropriate message saying what actually happened?
I think what you need to do is set headers of your response.
Here is an example:
var body = 'Sorry!';
response.writeHead(404, {
'Content-Length': body.length,
'Content-Type': 'text/plain' });
Refer to http://nodejs.org/api/http.html#http_response_writehead_statuscode_reasonphrase_headers for more information.

Node.js and the connect module: How do I get the message out of a request object sent to a web server

I'm using Node.js and connect to create a simple web server. I have something similar to the following code and I can't figure out how to access the actual request message body from the request object. I'm new to this so bear with me. I'm also taking out some of the stuff that's not necessary for the example.
function startServer(dir) {
var port = 8888,
svr = connect().use(connect.static(dir, {"maxAge" : 86400000}))
.use(connect.directory(dir))
/*
* Here, I call a custom function for when
* connect.static can't find the file.
*/
.use(custom);
http.createServer(svr).listen(port);
}
function custom(req, res) {
var message = /* the message body in the req object */;
// Do some stuff with message...
}
startServer('dirName');
Make sense? I've tried logging that object to the console and it is full of TONS of stuff. I can easily see headers in there plus the request URL and method. I just can't seem to isolate the actual message body.
You should include the connect.bodyParser middleware as well:
svr = connect().use(connect.static(dir, {"maxAge" : 86400000}))
.use(connect.directory(dir))
.use(connect.bodyParser())
.use(custom);
That will provide the parsed message body as req.body to your handler.
If you want the raw message body, you shouldn't use it but instead read the req stream yourself:
function custom(req, res) {
var chunks = [];
req.on('data', function(chunk) {
chunks.push(chunk);
});
req.on('end', function() {
var rawbody = Buffer.concat(chunks);
...do stuff...
// end the request properly
res.end();
});
}
if(req.method == "POST"){
var body = '';
req.on('data', function(data){
body += data;
});
}
Then body should contain your message if you posted correctly.
A better idea would be to use Express, then use the bodyparser middleware - which will give you this functionality out of the box without worrying about somebody hammering your server. The code above has NO functionality to worry about attacks - but it will get you started.

ExpressJS - contact external API

Here is the thing :
I have a client which sends data to a server. This server has to contact an external A.P.I. and send back its response to the client. I just can't figure out how and where I can contact the external A.P.I once the server has got the client data.
I route client data like this :
app.post('/getAutoComplete', routes.read);
routes.read retrieves the data within req.body. With my nodejs version (without express framework), I then request the api this way :
var http = require('http'), options = {
host : "192.168.1.38",
port : 8080,
path : "/myURL",
method : 'POST'
};
var webservice_data = "";
var webservice_request = http.request(options, function(webservice_response)
{
webservice_response.on('error', function(e){ console.log(e.message); });
webservice_response.on('data', function(chunk){ webservice_data += chunk;});
webservice_response.on('end', function(){res.send(webservice_data);});
});
webservice_request.write(req.body);
webservice_request.end();
The problem is that i'd like to use native expressJS method like app.post but I don't know how because :
Express (app) object is not available here (declared in app.js but not in the route file)
I don't know how to send POST data with app.post
Any suggestion ?
app.post('/getAutoComplete', routes.read);
// assuming routes.read lookes something like this
routes.read = function read(req, res) {
var http = require('http'), options = {
host : "192.168.1.38",
port : 8080,
path : "/myURL",
method : 'POST'
};
var webservice_data = "";
var webservice_request = http.request(options, function(webservice_response)
{
webservice_response.on('error', function(e){ console.log(e.message); });
webservice_response.on('data', function(chunk){ webservice_data += chunk;});
webservice_response.on('end', function(){res.send(webservice_data);});
});
webservice_request.write(req.body);
webservice_request.end();
};
Also check out https://github.com/mikeal/request It's the de-facto module for doing web requests in node.
routes.read is a function. You can call it with extra parameters, so for example
app.post('/getAutoComplete', function(req,res) {
var q = req.query.q; // or whatever data you need
routes.read(q, function(err, response) {
if (err) throw err;
return res.json(response);
});
});
Now make the routes.read function use the first parameter as the query and when it's gathered the response from the remote API, call the second parameter with any error as the first parameter and the response as the second one.
Update This answer has already been picked as an answer, but it'd be more helpful if I showed an example of routes.read, too:
routes.read = function(q, cb) {
// pretend we calculate the result
var result = q * 10;
if (result > 100) {
// call the callback with error set
return cb("q value too high");
}
// all is well, use setTimeout to demonstrate
// an asynchronous return
setTimeout(function() { cb(null, result) }, 2000);
};

Resources