I have an express API:
var bodyParser = require("body-parser");
app.use(bodyParser.json());
app.post("/adapter/mail", function(request, response) {
var body = request.body;
var id = body.id;
var params = {id: id};
Parse.Cloud.run("email", params, {
success: function(e) {
console.log("api: success");
respone.status(200).send("e");
},
error: function(e) {
console.log("api: error: " + JSON.stringify(e));
response.status(500).send(e);
}
});
});
Calling the API calls the Parse Cloud Code:
Parse.Cloud.define("email", function(request, response) {
console.log(JSON.stringify(request, null, 4));
response.success("ok");
});
In the console I see that console.log("api: success"); gets executed correctly, but the API request does not end, it times out despite the successful callback.
When Cloud Code returns response.error("error"); instead of response.success("ok"); the request does not timeout but ends immediately.
Why does the request time out on success?
Looks like you are missing an "s" on your callback
respon"s"e.status(200).send("e");
Related
I have written a programmable SMS feature using Twilio in nodejs. I have a message that has options to select and when user sends back any response I want to send an automated response using twilio.
I have completed all except after processing the response from user my automated response is not being delivered to user.
I keep getting above thing from my twilio dashboard.
Here is my response handler code..
app.post('/ui/sms',function(req, res) {
//req.headers['Content-type'] = 'text/xml';
//req.headers['Accept'] = 'text/xml';
try {
console.log('Processing Response', req.headers);
const MessagingResponse = require('twilio').twiml.MessagingResponse;
const twiml = new MessagingResponse();
const fromTwilio = isFromTwilio(req);
console.log('isFromTwilio: ', fromTwilio);
if (fromTwilio) {
let msg = req.body.Body||'';
if (msg.indexOf('1')>-1) {
twiml.message('Thanks for confirming your appointment.');
} else if (msg.indexOf('2')>-1) {
twiml.message('Please call 408-xxx-xxxx to reschedule.');
} else if (msg.indexOf('3')>-1) {
twiml.message('We will call you to follow up.');
} else {
twiml.message(
'Unknown option, please call 408-xxx-xxxx to talk with us.'
);
}
res.writeHead(200, { 'Content-Type': 'text/xml' });
res.end(twiml.toString());
}
else {
// we don't expect these
res.status(500).json({ error: 'Cannot process your request.' });
}
/*processSMSResponse(req, function(response) {
res.json(response);
});*/
} catch(e) {
res.json(e);
}
});
function isFromTwilio(req) {
console.log('REQ HEADER:::::::::\n', req);
// Get twilio-node from twilio.com/docs/libraries/node
const client = require('twilio');
// Your Auth Token from twilio.com/console
const authToken = 'xxxxxxxxxxxxxxxxx';
// The Twilio request URL
//const url = 'https://mycompany.com/myapp.php?foo=1&bar=2';
const url = 'https://xxxx.com/ui/sms';
var reqUrl = 'https://xxxx.com/ui/sms'
// The post variables in Twilio's request
//const params = {
//CallSid: 'CA1234567890ABCDE',
//Caller: '+14158675310',
//Digits: '1234',
//From: '+14158675310',
//To: '+18005551212',
//};
const params = req.body;
console.log('post params: ', params);
// The X-Twilio-Signature header attached to the request
try{
Object.keys(params).sort().forEach(function(key) {
reqUrl = reqUrl + key + params[key];
});
var twilioSignature = crypto.createHmac('sha1', authToken).update(Buffer.from(reqUrl, 'utf-8')).digest('base64');
//const twilioSignature = req.header('HTTP_X_TWILIO_SIGNATURE');
console.log('twilioSignature: ', twilioSignature);
} catch(e){
console.log(e);
}
return client.validateRequest(
authToken,
twilioSignature,
url,
params
);
}
I have explicitly tried setting headers but no use. I'm clue less on what twilio expects from me or how to modify headers.
{
"status": "Error",
"error": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response><Message>Please call 408-xxx-xxxx to reschedule.</Message></Response>"
}
I see this as body in Twilio console and it has the response that I need but could not send as a message..
Twilio Developer Evangelist here.
From looking at your code and trying it myself I can't see anything generally wrong with it. There are two potential failing points here though:
1) I can't see your isFromTwilio function. If that one fails it might cause an error and then return JSON instead of XML on your error handler. I don't know why it would reply with the TwiML in that JSON though.
2) The other behavior I could reproduce (except that the TwiML is not being sent in the response body) is when I don't include body-parser in the middleware chain. This will cause req.body to be undefined and therefore req.body.Body will throw an error that is then being caught and JSON is being returned.
Do you have body-parser included and properly included as a middleware? You can either do it this way:
const { urlencoded } = require('body-parser');
app.use(urlencoded({ extended: false });
or if you only want to use it for this one endpoint you can add urlencoded({ extended: false }) as an argument before your request handler:
app.post('/ui/sms', urlencoded({ extended: false }), function(req, res) {
I hope this helps.
Cheers,
Dominik
I'm trying to use a hook.io microservice to make a slack slash command bot. According to the docs I should be able to send an immediate response then a seperate POST later. But I cant get the immediate response and the later POST to both work.
Here is my test code.
module['exports'] = function testbot(hook) {
var request = require('request');
// The parameters passed in via the slash command POST request.
var params = hook.params;
data = {
"response_type": "ephemeral",
"text": "Immediate Response"
}
hook.res.setHeader('Content-Type', 'application/json');
console.log("returning immediate response")
hook.res.write(JSON.stringify(data), 'utf8', delay(params));
//calling end() here sends the immediate response but the POST never happens.
// but if end() is called below instead slack gives a timeout error but the POST succeeds.
//hook.res.end()
//test with 3.5 second delay
function delay(params) {
setTimeout(function () {post_response(params)},3500);
}
function post_response(params) {
console.log("posting delayed response")
// Set up the options for the HTTP request.
var options = {
// Use the Webhook URL from the Slack Incoming Webhooks integration.
uri: params.response_url,
method: 'POST',
// Slack expects a JSON payload with a "text" property.
json: {"response_type":"in_channel", "text":"Delayed response","parse":"full"}
};
// Make the POST request to the Slack incoming webhook.
request(options, function (error, response, body) {
// Pass error back to client if request endpoint can't be reached.
if (error) {
console.log(error);
hook.res.end(error.message);
} else {
console.log("post OK");
}
// calling end() here sends the POST but the immediate response is lost to a slack timeout error.
hook.res.end()
})
};
}
As detailed in the comments calling res.end() early means the immediate response gets sent but the POST never happens whereas delaying the res.end() until after POST means the delayed response is sent but it generates a timeout error from slack in the meantime.
I'm a javascript newbie so hopefully there is a simple solution that I've overlooked.
Once you call res.end() inside hook.io, the script will immediately abort and end processing. It's the equivalent of calling process.exit. If you fail to end the request, hook.io will eventually hit it's own Time-out Limit.
hook.io should be capable of responding back to Slack within the three seconds Slack requires.
Here is a guide which may help: Making a Custom Slack Slash Command with hook.io
Bad form to answer one's own question I know but the following worked for me using webtask so I include it here in case others find it useful.
var express = require('express');
var Webtask = require('webtask-tools');
var bodyParser = require('body-parser');
var request = require('request');
var app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
//visiting above url in browser is handled by get
app.get('/', function (req, res) {
console.log(req.query)
res.send('OK');
});
//post from slack handled here
app.post('/', function (req, res) {
var params = req.body;
console.log(params);
var data = {
"response_type": "ephemeral",
"text": "Immediate Response"
}
res.setHeader('Content-Type', 'application/json');
res.send(data);
// deliberate delay longer than Slack timeout
// in order to test delayed response.
setTimeout(function () { post_response(params) }, 3500);
});
function post_response(params) {
console.log("posting delayed response")
// Set up the options for the HTTP request.
var options = {
// Use the Webhook URL supplied by the slack request.
uri: params.response_url,
method: 'POST',
// Slack expects a JSON payload with a "text" property.
json: { "response_type": "in_channel", "text": "Delayed response", "parse": "full" }
};
// Make the POST request to the Slack incoming webhook.
request(options, function (error, response, body) {
if (error) {
console.log(error);
} else {
console.log("post OK");
}
})
};
module.exports = Webtask.fromExpress(app);
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.
I have a relatively simple ajax call that uploads a file from an input form to a server:
$(function(){
$("form").submit(function(){
var infile = $('#pickedfile');
var actFile = infile[0].files[0];
$.ajax(
{
type: "POST",
url: "http://localhost:3000/file_upload",
data: [
{
file: actFile
}],
dataType: 'text',
success: function ()
{
alert("Data Uploaded");
},
beforeSend: function ()
{
alert("Before Send");
return false;
},
error: function ()
{
alert("Error detected");
},
complete: function ()
{
alert("Completed");
}
});
});
});
And I have a node.js server that successfully receives the file, and reports back:
var express = require('express'),
wines = require('./routes/testscripts');
var app = express();
app.configure(function(){
app.use(express.bodyParser());
app.use(app.router);
});
app.post('/file_upload', function(req, res) {
//file should be in req.files.pickedfile
// get the temporary location of the file
// undefined if file was not uploaded
var tmp_path = req.files.pickedfile.path;
res.send("Hello, this is server");
});
});
app.listen(3000);
The file is uploaded successfully, and everything seems to work fine on the server side.
However, on the front end, none of the alerts are firing, so I'm not able to respond to any new data from the server. Is there some additional step that I'm missing?
Turns out this was a combination of two issues:
1) The jQuery, as identified in the comments, was being aborted.
2) Because the jQuery was canceled, it did not prevent the associated HTML form from submitting normally.
This combination meant that the form would submit and receive a response successfully, but because the jQuery code was silently failing, no callbacks were received.
I need to connect to a web page and return the status code of the page, which I've been able to achieve using http.request however the pages I need to request can take a long time, sometimes several minutes, so I'm always getting a socket hang up error.
I'm using the following code so far:
var reqPage = function(urlString, cb) {
// Resolve the URL
var path = url.parse(urlString);
var req = http.request({
host: path.hostname,
path: path.pathname,
port: 80,
method: 'GET'
});
req.on('end', function() {
cb.call(this, res);
});
req.on('error', function(e) {
winston.error(e.message);
});
};
What do I need to do to ensure that my application still attempts to connect to the page even if it's going to take a few minutes?
Use the request module and set the timeout option to an appropriate value (in milliseconds)
var request = require('request')
var url = 'http://www.google.com' // input your url here
// use a timeout value of 10 seconds
var timeoutInMilliseconds = 10*1000
var opts = {
url: url,
timeout: timeoutInMilliseconds
}
request(opts, function (err, res, body) {
if (err) {
console.dir(err)
return
}
var statusCode = res.statusCode
console.log('status code: ' + statusCode)
})
Add this if you don't want to use a higher level http client like request or superagent , then add this...
req.on("connection", function(socket){
socket.setTimeout((1000*60*5)); //5 mins
});