I have express server setup to listen post request and put the post request in message queue
var express = require('express');
var app = express();
app.use(express.bodyParser());
app.post('/test-page', function(req, res) {
var amqp = require('amqp');
var connection = amqp.createConnection({url: "amqp://guest:guest#localhost:5672"},{defaultExchangeName: ''});
connection.on('ready',function(){
console.log('connected');
var messageToSend = req.body;
var queueToSendTo = "xyz";
connection.queue(queueToSendTo,{'passive': true},function(){
connection.publish(queueToSendTo, messageToSend);
res.send(200);
connection.end();
});
});
});
app.setMaxListeners(0);
app.listen(80);
The above code is suppose to collect the post request and put in queue, If I send 10 requests, there would be more than 300 messages in queue. I don't understand this behaviour or may be my understanding of putting 'publish' call in 'ready' function is wrong since the 'connected' log message in above code is printed more than 10 for 10 post request.
Is it happening due to 'connection.end' not closing the connection?
I want to have each post request converted to a message in RabbitMQ,
Please advise if there is any better way.
(I am using latest master of node-amqp with rabbit-server-3.1.4-1 on ubuntu 12.04)
The issue it's that you are creating a connection to the queue for every post request to test-page. So you have to create this connection outside of the post handler.
I haven't tested the code but this should do the trick:
var express = require('express');
var app = express();
app.use(express.bodyParser());
var amqp = require('amqp');
var connection = amqp.createConnection({url: "amqp://guest:guest#localhost:5672"},{defaultExchangeName: ''});
connection.on('ready', function() {
console.log('connected');
});
app.post('/test-page', function(req, res) {
var messageToSend = req.body;
var queueToSendTo = "xyz";
connection.publish(queueToSendTo, messageToSend);
res.send(200);
});
app.setMaxListeners(0);
app.listen(80);
Related
I have a local server that is fully functioning when POSTs and GETs are sent from Postman or chrome rest apps etc. However, whenever I send it from an ESP8266 it fails as it follows:
This is my server side code:
router.get('/', function (req, res) {
var person = req.query.id;
console.log("1");
Person.find({person: personID} ,function (err, station) {
if(err) console.log(err.message);
console.log("3");
res.send('test');
console.log("4");
});
console.log("2");
});
Lines below are from console when request is sent from Chrome.
1
2
3
4
GET /api?id=ABKWTltz6Ug 200 21.829 ms - -
And the lines below are from console when request is sent from ESP8266.
1
2
GET /api?id=ABKWTltz6Ug - - ms - -
3
4
As you may notice logs 3 and 4 are after GET response line. My ESP8266 TCP connection lines match the HTTP Message Format:
GET /api HTTP/1.1
Host: *SERVER_IP_ADDRESS*
The problem raised when we switched from PHP to NodeJS backend server. ESP8266 used to connect and operate without problems back then. And FYI, everything also works fine if I remove the Person.find code block and move the res.send('test'); outside.
Another freshly written backend code to hopefully spot the error is below. This is the whole code. Which also returns the same error I've mentioned earlier above:
var express = require('express');
var app = express();
var router = express.Router();
var mongoose = require('mongoose');
var morgan = require('morgan');
app.use(morgan('dev'));
mongoose.connect('mongodb://localhost/test');
//mongoose.Promise = Promise;
var Test = mongoose.model('Test', { name: String });
router.get('/test', function (req, res) {
console.log("1");
var test1 = new Test({
name: "Name"
});
var query = test1.save();
query.then(function (doc) {
res.send('1').end();
console.log('3');
});
console.log("2");
});
app.use('/api', router);
var port = 9000;
app.listen(port,function(){
console.log('server started on', port);
});
I'm creating a web application which has two web portals, and a node server. First portal sends HTTP requests(POST) while the second web portal should show them. Then a user will type some text and send it back to the server through the socket and it should redirect it to the first portal. I've used socket.io for the communication happen between the second portal and the server, while the first one does it though post. I'm struggling with finding a way to receive the answer from the second web portal and send the answer back to the first one. Here's the code.
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
server.listen(5700);
io.on('connection', function (socket) {
console.log("connected" + socket.id);
});
app.post('/server', rawBody, function(req, res, next){
var question = req.query.question;
io.emit('question', {data: question});
io.on('answer', function(data) {
var body = {
response: "data.answer"
};
res.json(body);
});
});
As I've found io.on('answer', function(data) is incorrect. But what I need is something like this:
io.on('answer', function(data) {
var body = {
response: "data.answer"
};
res.json(body);
});
Could you please tell me how should I get the answer back from the socket and upon receive it, send the reply back to the first web portal.
Something like this:
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
server.listen(5700);
io.on('connection', function (socket) {
console.log("connected" + socket.id);
app.post('/server', rawBody, function(req, res, next){
var question = req.query.question;
socket.emit('question', {data: question});
});
socket.on('answer', function(data) {
var body = {
response: "data.answer"
};
res.json(body);
});
});
I'm new to node and got stuck with handling multiple async tasks.
Except from node, I've got another server (S1) which doesn't return data immediately to requests, it can returns multiple types of data and also can send notifications without requesting them specifically, so node have to listen to data from it , parse it and act accordingly.
The connection to this server (S1) is done by using:
S1 = net.createConnection({'host':S1Host, 'port': S1Port});
And node listens to data with:
S1.on('data', function(data){
S1DataParse(data);
});
I have to route the correct data (after parsing it) to a specific POST request.
app.post('/GetFooFromS1', function(req, res){
// Send request to S1
S1.write({'type':'foo'});
// If got the correct data sometime in the future, send response to the browser
res.setHeader('Content-Type', 'application/json');
res.json({'status':'success', 'value':S1FooData});
});
I tried to use the async module for that, but with no success.
What I was trying to do:
var asyncTasks = [];
app.post('/GetFooFromS1', function(req, res){
asyncTasks.push(function(callback){
// Send request to S1
S1.write({'type':'foo'});
});
async.parallel(asyncTasks, function(response){
res.setHeader('Content-Type', 'application/json');
res.json({'status':'success', 'value':response});
});
});
and another task in S1DataParse:
function S1DataParse(){
if(data.type='foo'){
asyncTasks.push(function(callback){
callback(data);
});
}
}
But, of course, the second task never added to the asyncTasks array. I really got stuck with that.
Can you please help me with that?
Thanks
-=-=-=- Edit -=-=-=-
Eventually, I came accross with events and EventEmitter().
From the POST request I call the function that sends requests to the data server (DataServerClientGet).
In this function I register a listener which will get the future data.
eventEmitter.on('getData', returnDataServerData);
It all works great except for one thing. Whenever I refresh the page or add other POST requests, I get an error:
Error: Can't set headers after they are sent.
It would be great if I solve this problem. Help me, please.
Thanks ;)
The whole code looks like this:
var express = require('express');
var app = express();
var http = require('http').Server(app);
var bodyParser = require('body-parser')
var net = require('net');
var events = require('events');
var dataServerHost = '127.0.0.1';
var dataServerPort = 12345;
var dataServerClient;
var logMsg;
var eventEmitter = new events.EventEmitter();
/*******************************************/
// Init
/*******************************************/
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static(__dirname + '/public'));
/*******************************************/
// Connect to the data server
/*******************************************/
DataServerConnect();
/*******************************************/
// Open listener on port 3000 (to browser)
/*******************************************/
http.listen(3000, function(){
logMsg = 'listening on *:3000';
console.log(logMsg);
});
/*******************************************/
// Routing
/*******************************************/
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
app.post('/GetDataFoo', function(req, res){
var msg;
var size;
msg ='\n{"Type":"Query", "SubType":"GetDataFoo","SearchFilter":""}';
size = msg.length;
logMsg = 'Client to DataServer: GetDataFoo';
console.log(logMsg);
DataServerClientGet('GetDataFoo', size, msg, res);
});
/*******************************************/
// Functions
/*******************************************/
function DataServerConnect(){
dataServerClient = net.createConnection({'host':dataServerHost, 'port': dataServerPort}, function(){
logMsg = 'Connected to DataServer ['+dataServerHost+':'+dataServerPort+']';
console.log(logMsg);
});
dataServerClient.on('data', function(data){
logMsg = 'DataServerData>>>\n'+data.toString()+'DataServerData<<<';
console.log(logMsg);
DataServerDataParse(data.toString());
});
dataServerClient.on('end', function(){
logMsg = 'Disconnected from DataServer';
console.log(logMsg);
});
}
function DataServerClientGet(type, size, msg, res){
dataServerClient.write('Type: Json\nSize: '+size+'\n\n'+msg, function(err){
var returnDataServerData = function returnDataServerData(results){
res.setHeader('Content-Type', 'application/json');
res.json({'status':'success', 'value':results});
}
eventEmitter.on('getData', returnDataServerData);
}
function DataServerDataParse(json){
if(json.Type=='GetDataFoo')
{
var MessageList = json.MessageList;
eventEmitter.emit('getData', MessageList);
}
}
-=-=-=- Edit -=-=-=-
The Error: Can't set headers after they are sent. caused by adding the same listener of the same type each time the DataServerClientGet was called and the res was sending multiple times.
I solved this one by adding: removeListener(event, listener)
right after the res, inside the function. Anyway, I think it's wrong and can cause problems if there will be multiple calling to DataServerClientGet with the same type etc.
There is a optional callback parameter that you can pass to write function(docs), something like :
S1.write({'type':'foo'},function(err){
if(err){
//Handle error
}else{
res.setHeader('Content-Type', 'application/json');
res.json({'status':'success', 'value':response});
}
})
This can work with post route , but in your 'data' listener ,you cant send data from server to client when there is not connection initialized by client (it is not bidireccional ) if you want bidireccional behavior you can check socket.io
I want to use nodejs server to receive messages from AMQP, then push those messages to web page through socket.io with redis.
The emit() function is invoked in the callback function consume of AMQP, and web UI can get those data. However, I can NOT find any data in redis?
codes
var redisPort = 6379,
redisHost = 'localhost';
var app = require('express')(),
http = require('http').Server(app),
io = require('socket.io')(http),
redisAdapter = require('socket.io-redis'),
redis = require('redis');
var
pub = redis.createClient(redisPort, redisHost),
sub = redis.createClient(redisPort, redisHost, {detect_buffers: true});
//
io.adapter( redisAdapter({pubClient: pub, subClient: sub}) );
app.get('/', function(req, res){
res.sendFile('index.html');
});
io.on('connection', function(socket){
console.log("web socket connection ...");
socket.join('room');
socket.on('disconnect', function(){
console.log("socketio diconnect...");
});
});
call back function in AMQP
function response(msg){
io.to('room').emit('online', msg);
}
...
ch.consume(queue, response, {noAck: true});
Am I right to use this API emit()? or miss any good trick?
I'm unsuccessfully attempting to create an pub-sub instant messaging service. I am unable to receive messages in browser client.
The following code is from my client1.html file. I believe the trouble I'm having relates to the client unsuccessfully subscribing to '/channel'. I've added the alerts and am receiving the 'BEFORE & AFTER' but not the 'DURING' and the message.text is not appearing on the console. Any thoughts as to why a client cannot see the messages on the browser would be appreciated.
var client = new Faye.Client('/faye',{
timeout: 20
});
alert("BEFORE client subscription");
client.subscribe('/channel', function(message) {
$('#messages').append('<p>' + message.text + '</p>');
alert("DURING client subscription");
console.log(message.text);
});
alert("AFTER client subscription");
The browser console repeats the following error repeatedly:
POST http://my.server#server:8000/faye 404 (Not Found)
This error points to 'faye-browser.js:2023' which refers to the following line:
xhr.send(Faye.toJSON(message));
EDIT
This is is the server.js file
var fs = require("fs");
var config = JSON.parse(fs.readFileSync("config.json"));
var host = config.host;
var port=config.port;
var express = require("express");
var Faye = require('faye');
var bayeux = new Faye.NodeAdapter({mount: '/faye', timeout:45});
var app = express();
app.configure(function(){
app.use(express.bodyParser());
app.use(express.static('/'+__dirname));
});
app.post('/message', function(request, response){
bayeux.getClient().publish('/channel', {text:request.body.message});
console.log('broadcast message:' + request.body.message);
response.send(200);
});
bayeux.attach(app);
app.listen(port);
I've just configured Faye for our application, you are doing
bayeux.attach(app);
app.listen(port);
did not work for me, what worked is this
bayeux.attach(app.listen(port, function() {}));
I also think that you should use the whole url when you are creating Faye, not just the final part, like so:
var client = new Faye.Client('http://my.url.com/faye', { timeout: 20 });