I'm trying to build a slack app and to configure it properly I need to do successive Https get request. I use callbacks methods to handle it, the first one calls the second one without any problem but then the third one never starts, and my program is stuck.
Here is my code :
//CREATE THE app OBJECT
//---------------------
var app = express();
app.use(bodyParser());
var port = process.env.PORT || 5000;
//CALLBACK FUNCTIONS
//------------------
// USE THE SLACK BUTTON TO CREATE THE APP
boutonSlack = function(req, res,next) {
res.send('<a href="https://slack.com/oauth/authorize?scope=bot,incoming-webhook,commands&client_id='+process.env.CLIENT_ID+'">'
+'<img alt="Add to Slack" height="40" width="139"'
+'src="https://platform.slack-edge.com/img/add_to_slack.png" '
+'srcset="https://platform.slack-edge.com/img/add_to_slack.png 1x, '
+'https://platform.slack-edge.com/img/add_to_slack#2x.png 2x" /></a>');
console.log('cb0:le bouton slack s\'affiche');
next();
app.get('/redirect/',oauthFlow);
};
//GET THE CODE PARAMETER AND PERFORM THE OAUTH FLOW
oauthFlow = function(req, res, next){
process.env.CODE = req.query.code;
console.log('cb1 : le code est récupéré');
https.get('https://slack.com/api/oauth.access?client_id='+process.env.CLIENT_ID+'&client_secret='+process.env.CLIENT_SECRET+'&code='+process.env.CODE, (res) => {
res.on('data', (chunk) => {
var result = JSON.parse(chunk);
process.env.SLACKTOKEN = result.access_token;
process.env.SLACK_BOT_TOKEN = result.bot.bot_access_token;
console.log('cb2 : le token est récupéré')
next();
app.get('/websocket/',ouvertureWebsocket);
});
});
};
//THIS CALLBACK NEVER STARTS
//PERFORM THE rtm.slack METHOD
ouvertureWebsocket = function (req, res, next) {
console.log("working");
https.get('https://slack.com/api/rtm.start?token='+process.env.SLACK_BOT_TOKEN, (res) => {
res.on('data', (chunk) => {
var result = JSON.parse(chunk);
console.log(JSON.stringify(result));
console.log('cb3 : ouverture du web socket');
next();
});
});
res.end();
}
//RUN THE CALLBACK FUNCTIONS
//--------------------------
app.get('/',boutonSlack);
app.listen(port, function () {
console.log('Ready, listenning port '+port);
});
This raises suspicions:
app.get('/redirect/',oauthFlow);
not that theres anything wrong with the code line, it's just that its inside a handler for the '/' route. Normally you'd define all route handlers on the top level and not anymore in any handlers.
Related
I have a NodeJS server script, which works like a charm on my local dev environment. But in (beta) production the webserver times out at every request. I've set this up fairly straight forward but I'm unsure how to fix it - or even where to look for a solution. Below is a simplified implementation, my logic for handling post request has been removed. What am I overlooking?
var requestListener = '';
// define the request listener, to handle incoming requests
requestListener = function (req, res) {
try {
if (req.method == 'POST') {
var queryString = '';
req.on('data', function (data) {
queryString += data;
});
req.on('end', function () {
// my logic is in here
res.end(JSON.stringify({ err: false, msg: 'all fine' }));
});
}
res.writeHead(200);
res.end();
} catch (error) {
res.writeHead(400);
res.end(error);
}
}
// boot the webserver
server = http.createServer(requestListener);
server.listen(8080);
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?
});
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
The thing I want to do is modify the response body.
For this I am using a middleware that gets called at every request.
To achieve it, I took a demo application from github https://github.com/ccoenraets/nodecellar . I added a middleware in the server.js similar to the example given on express logging response body.
Still I am unable to modify the response body, as res.send = function (string) does not get called.
Below mentioned is the code. Please let me know what wrong am I doing here.
var express = require('express'),
path = require('path'),
http = require('http'),
wine = require('./routes/wines');
var app = express();
app.configure(function () {
app.set('port', process.env.PORT || 4000);
app.use(express.logger('dev')); /* 'default', 'short', 'tiny', 'dev' */
app.use(express.bodyParser()),
app.use(express.static(path.join(__dirname, 'public')));
app.use(logResponseBody);
});
app.get('/wines', wine.findAll);
app.get('/wines/:id', wine.findById);
app.post('/wines', wine.addWine);
app.put('/wines/:id', wine.updateWine);
app.delete('/wines/:id', wine.deleteWine);
http.createServer(app).listen(app.get('port'), function () {
console.log("Express server listening on port " + app.get('port'));
});
function logResponseBody(req,res,next){
var send = res.send;
console.log("send resp is: "+send);
res.send = function (string) {
var body = string instanceof Buffer ? string.toString() : string;
console.log("Body found is: "+body);
body = body.replace(/<\/head>/, function (w) {
return 'Modified head' + w;
});
send.call(this, body);
};
res.on('finish', function(){
console.log("Finished " + res.headersSent); // for example
console.log("Finished " + res.statusCode); // for example
})
next();
}
PS: I am starting a new thread for a similar question as I have less than 50 reputation.Therefore cant add comments there.
The best way to add middleware to an express app is to use the app.use method, so you can remove the whole http.createServer block and replace it for something like
app.use(function(req, res, next) {
//do everything you want to happen on every request
next();
});
app.listen(app.get('port'), function() {
console.log('listening on port ' + app.get('port'));
});
For more info on app.use, check the express app use documentation.
I have this basic express app:
var express = require('express');
var app = express();
var PORT = 3000;
var through = require('through');
function write(buf) {
console.log('writing...');
this.queue('okkkk');
}
function end() {
this.queue(null);
}
var str = through(write, end);
/* routes */
app.get('/', function(req, res){
res.send("Hello!");
})
app.post('/stream', function(req, res){
var s = req.pipe(str).pipe(res);
s.on('finish', function() {
console.log('all writes are now complete.'); // printed the first time
});
});
/* listen */
app.listen(PORT, function () {
console.log('listening on port ' + PORT + '...');
});
When I post some data to /stream endpoint for the first time after starting the server I get okkk as the response which is what I expect. However, after that, any requests to /stream endpoint just timeout and not return any response.
Why is it so? What's exactly happening here?
I had this same problem and looks like res was not being finished properly. So I added a callback to my stream and ended que res myself. That fixed my problem:
stream.on('end', () => res.end());
stream.pipe(res);
It worked when I replaced req.pipe(str).pipe(res) with req.pipe(through(write, end)).pipe(res) which essentially makes sure that a new instance of through stream is created for every request.