Extracting POST request data from Express in Nodejs - node.js

I have a fairly simple express server that is designed to take external client data and publish it via mqtt to a gateway. It works perfectly with a hardcoded variable but I can't figure out how to extract the actual data from the POST request, which is as follows (it prints to the console just fine):
const postData = app.post('/send-data', function (req, res) {
console.log('connected', req.body);
res.status(200).json(req.body)
});
I need to get the req.body data out of that and into the following code that publishes the data to the topic:
client.on('connect', function () {
console.log('connected!');
client.publish('iot-2/type/wtlType/id/channel100/evt/event/fmt/json', publishData);
client.end();
});
publishData will just be the stringified json response.
This is the create server code if that helps:
https.createServer(options, app).listen(30002, () => {
console.log('Listening')
});

If I understand correctly your question is about the logic of getting the req.body published by the client. If so, then something like this should work:
let connected = false;
client.on('connect', function () {
console.log('connected!');
connected = true;
});
const postData = app.post('/send-data', function (req, res) {
console.log('connected', req.body);
res.status(200).json(req.body)
client.publish('iot-2/type/wtlType/id/channel100/evt/event/fmt/json', JSON.stringify(req.body));
client.end(); // are you sure you want this? can there not be more messages to broadcast?
});

Related

Edit the response after a redirect (node.js & express)

I have a Nodejs express app which receives POST requests (XML) and simply redirects them to a different host replying to the original caller (also with an XML message).
var app = require('express')();
app.post('/', function(req, res) {
res.redirect(307, 'http://localhost:8888/');
});
app.listen(3000, function() {
console.log('Application listening on http://localhost:3000/');
});
What I am trying to achieve is to modify the response from the second host (localhost:8888). How do I intercept and edit the response from the second host before it reaches the original caller?
I cannot figure it out from the documentation so any help would be very appreciated, thank you.
You cannot do that as the response from server 2 is fetched by the client handling the redirect (e.g. your browser). You have to fetch the response yourself in the server side, modify it and send it back.
var app = require('express')();
var request = // your preferred http library
app.post('/', function(req, res) {
request.get('http://localhost:8888/', function (err, response) {
if (err) {
return res.error(err);
}
// Here you have the response, you can modify it.
res.send(response.body);
});
});
app.listen(3000, function() {
console.log('Application listening on http://localhost:3000/');
});

Socket.io multiple response instead of one

I'm facing a problem with socket.io and node js.
Context
I have two servers, one of them is processing heavy jobs and the other is responding to the clients.
The main case is the following one :
The client request data
The "mid server" looks if I have this data in the database. If I haven't, itsend a request to the second server
The second server performs the research.
Once its done, the second server push de data to the "mid server"
The mid server finally push the data to the client (and persists it for future client requests)
Here's the sample code
Client
<script type="text/javascript"/>
var socket = io('https://localhost:9091', {'forceNew': true);
// send a request to the mid server
socket.emit('request', data);
socket.on('response', async (response) => {
// when the mid server responds, the response is printed
$('#container').append(response);
});
</script>
Mid server
const app = require('express')();
const http = require('http').createServer(app);
const io = require('socket.io')(http);
// in order to use this server as a Socket.io client
const secondServer = require('socket.io-client').connect('http://localhost:9092');
app.set('view engine', 'ejs');
app.get('/', (req, res) => {
res.render('index', {})
});
io.on('connection', async (socket) => {
console.log('User connected');
// On client request
socket.on('request', async (data) => {
console.log('Requesting from ' + socket.id);
// The same request is transmited to the second server
secondServer.emit('request', data);
});
// Once the second server has finished his job
secondServer.on('response', async (data) => {
console.log('Responding for ' + socket.id);
// I send the data back to the client
socket.emit('response', data);
});
socket.on('disconnect', () => {
socket.disconnect();
});
});
// port is 9091
http.listen(port, () => {
console.log('Server listening on port ' + port);
});
Second server
const io = require("socket.io").listen(9092);
io.on("connection", function (socket) {
socket.on('request', async () => {
// await in order to wait the heavyJob to be done before sending the response
var data = await heavyJob()
// Send back the data to the mid server
socket.emit('response', data);
});
});
Problem
The problem I'm facing is, if I refresh the client page, the mid server will send twice the data, once to the old socket and the once for the new one as so :
I have also tried to respond to the client with socket.emit('response', data) on mid server side and socket.on('response', (data) => {}) on client side instead of using callback function. It doesn't change anything.
Do I misunderstanding something ?
Thanks for your help
Edit
It doesn't only happen when the client is refreshing his page. It happens when two different clients send a request at the same time. The server is responding four times, two times for each client.
You are right Nico, I didn't recognized callback can't be reached.
It was my mistake.
According to your edited code, you can pull out "secondServer.on('response'.." from "io.on('connection'"'s callback.
You can try below and I hope this would be helpful.
Mid Server
io.on('connection', async (socket) => {
console.log('User connected');
// On client request
socket.on('request', async (data) => {
console.log('Requesting from ' + socket.id);
// The same request is transmited to the second server
// give data and socket.id to secondServer.
secondServer.emit('request', {data:data, id:socket.id});
});
// Once the second server has finished his job
socket.on('disconnect', () => {
socket.disconnect();
});
});
secondServer.on('response', async (reply) => {
const {id, data} = reply;
console.log('Responding for ' + id);
// I send the data back to the client
io.to(id).emit('response', data);
});
Second Server
const io = require("socket.io").listen(9092);
io.on("connection", function (socket) {
socket.on('request', async (req) => {
// await in order to wait the heavyJob to be done before sending the response
const {id} = req;
var data = await heavyJob();
const reply = { id, data };
// Send back the data to the mid server
socket.emit('response', reply);
});
});
I think you need pull out "secondServer.on('response'.." code from "socket.on('request',..." callback.
io.on('connection', async (socket) => {
console.log('User connected');
// On client request
socket.on('request', async (data, callback) => {
console.log('Requesting from ' + socket.id);
// The same request is transmited to the second server
secondServer.emit('request', data);
});
secondServer.on('response', async (data) => {
console.log('Responding for ' + socket.id);
callback(data.images);
});
});

Socket.io: Failed GET requests in the console

I am trying to add socket.io to my code, and the following failed GET request is repeatedly printed to the console whenever I run the website on my localhost.
GET http://localhost:4000/socket.io/?EIO=3&transport=polling&t=MMNC8I9 0 ()
I do not understand what is sending this request. The socket works, although not entirely in the way I intended it to*.
*I am trying to build a real-time application that works with several clients, and at the moment only one client is being updated at any given time. As I am still learning, I am not sure if this is a normal behaviour or not, but I want to fix the failed request error before I dive into that!
How do I fix the issue? Thank you in advance!
Code below:
server.js
const client=require("socket.io").listen(4040).sockets;
const app = express();
mongoose.connect('mongodb://localhost/<dbname>?replicaSet=rs');
mongoose.connect(config.db);
const db = mongoose.connection;
db.once("open", () => {
console.log(">>> 🖥️ MongoDB: Connection successful");
app.listen(9000, () => {
console.log('Node server running on port 9000');
});
// Connect to Socket.io
client.on("connection", function(){
let queries = db.collection('queries');
// Create function to send status
sendStatus = function(s) {
socket.emit("status", s);
}
});
});
app.post('/query', (req, res, next) => {
<some code omitted>
doc.save()
.then(result => {
socket.emit("query", res);
res.send({
result
});
}
});
Queries.js
constructor(props) {
...
var socket = io.connect("http://localhost:4000/");
if (socket!= undefined) {
socket.on("query", function() {
this.loadQueries();
});
}
index.html
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.4/socket.io.js"></script>

Forward request to ws client and wait for response Express

I'm trying to build an endpoint that will receive a request, emit the request data to a WebSocket client, wait for an event, then send back the response using express + socketio. This question is similar to it: Wait for socketio event inside express route
1) Receive request at http://localhost:3000/endpoint
2) Emit the event to web sockets as 'req'
3) Wait for 'res' event from ws
4) Send the received events details as the response of express.
Here is how I'm implemented:
server.js
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
var socket;
io.on('connection', function (s) {
socket = s;
});
http.listen(3000);
app.get('/endpoint', function (req, res) {
console.log('new request')
io.emit('req', { data: 'hello' });
socket.on('res', function (data) {
res.status(200).json(data);
});
});
index.html
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
socket.on('req', (data) => {
console.log(data)
socket.emit('res', data);
});
</script>
The script works fine for the first request on /endpoint. But if i hit the url again, it says
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent
to the client
Please note that:
socket.on('res', function (data) {
res.status(200).json(data);
});
Is being called each time a socket is sending a response, thus showing the above error. You should unbind the listener inside the callback function.
Keep an array of express responses and set an id to each request. So it can be used later and delete if needed.
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var timeout = require('connect-timeout');
var uuid = require('uuidv4');
var _ = require('lodash');
app.use(timeout('10s'));
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
let responses = []
io.on('connection', (socket) => {
socket.on('res', (e) => {
var obj = _.find(responses, r => r.id === e.id);
obj.res.send(e)
_.remove(responses, r => r.id === e.id);
})
})
app.get('/endpoint', (req, res) => {
const id = uuid()
io.emit('req', { id, ip: req.ip, header: req.headers, method: req.method });
responses.push({ id, res })
});
http.listen(3000);
You're trying to do two different async tasks for the same data.
First, take your socket.on('res'...) out of the app.get().
Send back res.status(200) immediately with express to say you received the request and it is processing. Then send the socket message to the client using socket.io when it's complete. You'll want to save the connected users socket client ID and use io.to(socketId).emit(...data...) to do this
the other option is what I always do (assuming it's not a crazy large payload of data you're sending) Just use socket.io for the whole process.
client
function makeRequest () {
socket.on('data-complete--error', function ( error ) {
// ... message to user :(
// also remove these handlers when finished
socket.off('data-complete--error');
socket.off('data-complete--success');
});
socket.on('data-complete--success', function ( data ) {
// ... message to user :)
// ... handle data
// also remove these handlers when finished
socket.off('data-complete--error');
socket.off('data-complete--success');
});
socket.emit('request-data');
}
makeRequest();
server
move your stuff out and handle without using express at all

Why does not sending data io.sockets.emit and socket.broadcast.emit

Tried different methods, but the data is sent to a maximum of one or two clients. How to send data to all the clients connected to the server ? What am I doing wrong?
Server.js:
var PORT = 3000;
var options = {
// 'log level': 0
};
var express = require('express');
var app = express();
var http = require('http');
var server = http.createServer(app);
var io = require('socket.io').listen(server, options);
server.listen(PORT);
app.get('/', function (req, res) {
res.sendfile(__dirname + '/attantions/templates/.default/template.php');
});
io.sockets.on('connection', function (client) {
client.on('attantion', function (data) {
try {
// Tried so
io.sockets.volatile.emit('attantion', data);
// And tried so
io.sockets.emit('attantion', data);
client.emit('attantion', data);
client.broadcast.emit('attantion', data );
} catch (e) {
console.log(e);
client.disconnect();
}
});
});
Client.js:
socket.emit("attantion", data);
socket.on('attantion', function (data) {
pushData(data);
});
See this post for different options for socket.io messages
Send response to all clients except sender (Socket.io)
io.sockets.on('connection', function (client) {
client.on('attantion', function (data) {
//client.emit('attantion', data ); // This will send it to only the client
//client.broadcast.emit('attantion', data); // This will send it to everyone but this client
io.emit('attantion', data); // This will send it to all attached sockets.
});
});
Edit
I wonder if this post can help you?
Socket.io - Cannot load file
I was curious how sending the php file to the client through node.js works? are you using another framework?
Could you show more of what your client code looks like? loading the lib and the instantiation of the socket.

Resources