Im trying to request a status of a user, with a POST from node.js to a PHP file.
My issue is that the webservice Im calling is VERY slow to reply(4 sec), so I think the .then finishes before the 4 sec, and therefore returns nothing. Got any idea if i can extend the time for the request?
requestify.post('https://example.com/', {
email: 'foo#bar.com'
})
.then(function(response) {
var answer = response.getBody();
console.log("answer:" + answer);
});
I am not that knowledgeable on requestify but are you sure you can use post to a https address? In the readme only requestify.request(...) uses a https address as an example. (see readme)
One tip I can definitely give you though is to always catch your promise:
requestify.get(URL).then(function(response) {
console.log(response.getBody())
}).catch(function(err){
console.log('Requestify Error', err);
next(err);
});
This should at least give you the error of your promise and you can specify your problem.
Each call to Requestify allows you to pass through an Options object, the definition of that object is described here: Requestify API Reference
You are using the short method for POST, so I'll show that first, but this same syntax will work for put as well, notice that get, delete, head do not accept a data argument, you send url query parameters through the params config property.
requestify.post(url, data, config)
requestify.put(url, data, config)
requestify.get(url, config)
requestify.delete(url, config)
requestify.head(url, config)
Now, config has a timeout property
timeout {number}
Set a timeout (in milliseconds) for the request.
So we can specify the a timeout of 60 seconds with this syntax:
var config = {};
config.timeout = 60000;
requestify.post(url, data, config)
or inline:
requestify.post(url, data, { timeout: 60000 })
So lets put that together now into your original request:
as #Jabalaja pointed out, you should catch any exception messages, however you should do this with the error argument on the continuation.
(.then)
requestify.post('https://example.com/', {
email: 'foo#bar.com'
}, {
timeout: 60000
})
.then(function(response) {
var answer = response.getBody();
console.log("answer:" + answer);
}, function(error) {
var errorMessage = "Post Failed";
if(error.code && error.body)
errorMessage += " - " + error.code + ": " + error.body
console.log(errorMessage);
// dump the full object to see if you can formulate a better error message.
console.log(error);
});
Related
This is the code:
router.post("/form", async (req, res) => {
try {
let { name, email, password } = req.body;
let user = await User.create({
name,
email,
password,
});
if (!user) return res.status(501).send("Something went wrong");
let token = await user.getSignedToken();
console.log(token); //Server logs this
user.emailToken = await user.verifyEmail();// This property is not being added in the saved mongodb document. It should, but again idk why it's not
await user.save({ validateBeforeSave: false });
console.log(user); // Server doesn't log this
const options = {
expires: new Date(
Date.now() + process.env.JWT_COOKIE_EXPIRE * 24 * 60 * 60 * 1000
),
};
console.log(options); // Server doesn't log this
res.cookie("token", token, options);
res.send("Check email for activation");
} catch (ex) {
res.send(ex);
}
});
Below is the verifyEmail method (in userSchema.. I'm using mongoose):
userSchema.methods.verifyEmail = async function () {
let emailToken = this._id + crypto.randomBytes(10).toString("hex");
let emailTokenHashed = await crypto
.createHash("sha256")
.update(passwordToken)
.digest("hex");
this.emailToken = emailTokenHashed;
return emailToken;
};
Now, it should send "Check email for activation", right? But, it's sending an empty response object. Also, if you see in the code, the server is logging only one console.log (i.e. the first console.log). But, it is sending a cookie (I checked via postman). So, what's the issue here?
This code sends res.send("Check email for activation"); or res.send(ex);. Since you say that:
console.log(options); // Server doesn't log this
then one of your await statements must be hitting a rejected promise and sending you to the catch. Add console.log(ex) right before res.send(ex) to see what the error is so you have this:
} catch (ex) {
console.log("got error", ex);
res.send(ex);
}
And, then see what you get in the log.
In general you never want to send an error object directly because most of its properties are non-enumerable so they won't get sent as JSON and that may make the error object completely empty when it gets converted to JSON and thus isn't useful to the client at all. Instead, log the error on your server and send a 500 status:
res.sendStatus(500);
Or, if you want to send an error object construct your own error object with regular, enumerable properties and send that.
Anyway, once you add the console.log(ex) to your server, it should tell you what the actual rejected promise is and that will show you what's going wrong with the request. ALWAYS log errors on the server to help you see and solve problems like this.
For some reason, the success and error handlers of my ajax request is not working as expected.
My node server performs correctly and gives me the right results, but whatever is in the error section of my ajax request executes regardless.
I checked other posts and they seem to be doing the same thing I am. I can't figure out what's happening.
My ajax code:
$.ajax({
url: path,
method: 'POST',
dataType: 'JSON',
data: items,
success: function(response)
{
alert('Tweety Logs sent successfully.')
},
error: function(err)
{
alert('Tweety Logs not sent.')
}
});
The function in my server:
function log(req,res)
{
var breed = req.body.breed;
var list = req.body.logs;
try {
fs.appendFileSync("Logs/log.dat", JSON.stringify(breed) + "logs:\r\n");
for(let i = 0; i < list.length; i++)
{
fs.appendFileSync("Logs/log.dat", JSON.stringify(list[i]) + "\r\n");
console.log('Added to Logs/log.dat - ' + JSON.stringify(list[i]));
}
res.sendStatus(200);
}
catch (err) {
console.log('Error writing to the file: ' + err.message)
res.sendStatus(500);
}
}
The error bit of ajax gets called everytime even if it's successful.
Any idea why?
If you add console log in your server code it it won't be a json response. You need to add json data to your res.send instead of console.log
And remove console.logs
It been awhile I used Ajax last but you can try out axios or fetch they will make your life much easier.
Axios handle error better by using the catch block.
Check this links for more help and details.
https://alligator.io/js/axios-vanilla-js/
https://alligator.io/js/fetch-api/
UPDATE: I had a mistake on my http request endpoint. I had not set the appropriate authentication options so that fixed a lot of errors possibly this specific one.
My question is similar to one here:
Node.js Lambda function returns "The response is invalid" back to Alexa Service Simulator from REST call
However the solution to that question does not solve my problem. So I make an http request call to an xsjs service in Hana cloud. I am getting the 'response is invalid' error message. I can't see why. Here is my function:
// Create a web request and handle the response.
function httpGet(query, callback) {
console.log("/n QUERY: "+ query);
var host = 'datacloudyd070518trial.hanatrial.ondemand.com';
var path = '/LocationInformation/getLocationInfo.xsjs?location=';
var hostname = 'https://' + host + path + query;
var auth = 'user1:D1anafer';
var req = http.request({'hostname': hostname,
'auth': auth
}, (res) => {
var body = '';
res.on('data', (d) => {
body += JSON.stringify(d);
});
res.on('end', function () {
callback(body);
});
});
req.end();
req.on('error', (e) => {
console.error(e);
});
}
And the function that calls it:
'getNewsIntent': function () {
//self = this;
httpGet(location, function (response) {
// Parse the response into a JSON object ready to be formatted.
//var output = JSON.parse(response);
//output = output['change'];
var output = response;
var cardTitle = location;
var cardContent = output;
alexa.emit(':tellWithCard', output, cardTitle, cardContent);
});
},
Thank You
-Diana
Inside your AWS account go to your Lambda function and click on the monitoring tab, where you should see "View Logs in Cloudwatch" in the right hand corner. If you click that link and you should see the errors that are being produced.
You can also use console.log() to log any information being returned from your REST api, which will be logged in cloudwatch and can help you see where your errors are.
This is just a guess from the top of my head. To really help some detailed error message would be required like mentioned about.
But just a guess: Your http.request() is using the http module (https://nodejs.org/api/http.html) and your are accessing the a https resource. If so there is a https (https://nodejs.org/api/https.html) module or use something like axios https://www.npmjs.com/package/axios or requestjs (https://github.com/request/request) this will handle both.
Like I said just a blind guess without detailed error message and seeing your require statements but I am happy to dive deeper if you happen to have details.
HTH
Your callback from the Lambda has to return a valid status code and body. Like this:
let payload = {
statusCode: 400,
body: JSON.stringify('body'),
headers: {"Access-Control-Allow-Origin": "*"}
};
callback(null, payload);
On top of that, to call this from client side code, you have to pass the CORS header back.
I am trying to do a simple xhttp GET request to an express.js server. Unfortunately I get no response data with this code. The connection is fine as I have successfully used "res.send" to send a body back from the server.
I am not sure if my use of "findOne" on the server is incorrect or if my use of xhttp on the client is incorrect. I suspect it is the client.
I'd appreciate any advice.
* CLIENT CODE *
function getfood() {
var xhttp = new XMLHttpRequest();
xhttp.open("GET", "http://localhost:3000/clientfood", true);
xhttp.send();
}
* SERVER CODE - Express.js / Node *
app.get('/clientfood', cors(), (req, res) => {
//res.send('test'); //this works at least
db.collection('quotes').findOne({
"_id": ObjectId("12345")
},
{
name: 1,
quote: 1
})
})
xhttp GET request to an express.js server - nothing returned
Your server code does not return a response. You need to do something like res.send(...) or res.json(...) to return a response back to the caller and you need to do that in the callback that your database provides for communicating back the result of a query (in most DBs, you can either use a plain callback or a promise).
Your client code does not listen for a response. Example for how to do that shown here on MDN and would typically be:
function getfood() {
var xhttp = new XMLHttpRequest();
xhttp.addEventListener("load", function() {
if (xhttp.status === 200) {
// have data in xhttp.responseText, process it here
} else {
// got some other response here
}
});
xhttp.open("GET", "http://localhost:3000/clientfood", true);
xhttp.send();
}
Thanks so much - especially #jfriend00. I have a lot to learn about how these frameworks work. After taking your advice about SEND I had a little trouble seeing the result on my frontend. I got the message "promise pending". I fixed that with the code suggested in this post.
Express - Promise pending when loop queries
Also I modified my findOne function to grab the entire object for my id.
Final code:
app.get('/clientfood', cors(), (req, res) => {
mydata = db.collection('quotes').findOne(
{
"_id": ObjectId("12345")
})
// promise code
Promise.all([mydata]).then(listOfResults => {
res.send(JSON.stringify(listOfResults)) //for example
}, err => {
res.send(500, JSON.stringify(err)); // for example
});
})
Overview
I'm developing an MVC application with NodeJS. When the application loads for the first time, the database object (using a pool) is created.
var pool = mysql.createPool({connectionLimit: 150, host: __host,
user: __user, password: __password,
database: __database})
module.exports = pool
When a request is received, a Controller object is created, which creates a Model to perform actions. The model gets a connection from the pool, performs the action, and releases the connection back to the pool.
//router snippet
router.get('/post_data', function(req, res){
router.setRequestAndResponse(req, res)
var post_data = new Post_Data()
post_data.processDataFromGet(router)
})
//controller code snippet
Post_Data_Controller.prototype.processDataFromGet = function(router){
var controller_obj = this
var data_array = {}
var req = router.req, res = router.res
//retrieving data from request and passing to the data_array
controller_obj.model.create(data_array, function(result){
var xml = xmlbuilder.create("response")
if (result.code == "error"){
xml.e("code", "error")
xml.e("message", result.error_message)
}else if (result.code == "success"){
xml.e("code", "success")
}
controller_obj.sendResponse(router.res, xml, "xml")
})
}
Post_Data_Controller.prototype.sendResponse = function(res, response, type){
if (type == "json"){
res.set({"Content-Type": "application/json", "Content-Length": JSON.stringify(response).length})
res.send(response)
}else{ /* Default type is XML */
res.set({"Content-Type": "application/xml", "Content-Length": response.end({pretty: true}).length})
res.send(response.end({pretty: true}))
}
}
//Model snippet
Post_Data.prototype.create = function(data_array, callback){
/* data validation */
var fail = false, error_data = {}
if (fail) {callback({code: "fail", cause: error_data}); return;}
//the next 2 lines do not throw an error when uncommented
//callback({code: "fail", cause: "how's it going"});
//return;
__db_pool.getConnection(function(err, db_conn){
// the next two lines throw an error for two or more requests coming in at the same time
callback({code: "fail", cause: "how's it going"});
return;
if (err) { callback({code: "error", error_message: err}); return;}
callback({code: "fail", cause: "how's it going"});
return;
db_conn.query("sql command", [data_array],
function(err, result){
if (err){ callback({code: "error", error_message: err}); return;}
if (result && result.length > 0){ //affiliate and listing exist
data_array.listing_id = result[0].listings_id
var data = [data_to_insert]
db_conn.query("sql command here", data,
function(err, result){
db_conn.release()
if (err){ callback({code: "error", error_message: err}); return;}
if (result && result.affectedRows > 0) {
callback({code: "success", data: {data_to_be_returned}})
}else {callback({code: "error", error_message:"Error inserting data"}); return}
})
}else{
callback({code: "fail", cause: "error to send back"})}
})
})
}
Problem
These requests are web service requests. If I send one GET request, no error happens; however, when I send two or more concurrent requests, I receive this error:
/project_path/node_modules/mysql/lib/protocol/Parser.js:82
throw err;
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (http.js:689:11)
at ServerResponse.res.set.res.header (/project_path/node_modules/express/lib/response.js:549:10)
I traced the culprit to the specific line in the Model code pasted above. It seems that for some reason, once the model obtains a connection from the pool for the second request, it somehow interferes with the first request. Both requests still insert the proper data into the database; however, the second and subsequent requests can't send a response without throwing an error anymore.
I have performed the requests with GET, POST, and PUT content-types; only GET throws the error. All the other content-types don't throw any error, even with over one thousand concurrent requests.
Here's the web service code for the GET requests; it's the same for the other content-types except for the content-type changes and the data being put in the body.
for(var i=0; i less than 5; i++){
sendAsGet()
i++
}
function sendAsGet(){
try{
var data = "?data_to_be_sent"
var uri =url.parse("http://localhost:4000/post_data")
var options = {hostname: uri.hostname, port: uri.port, method: "GET",
path: uri.path + data, agent: false}
request = (uri.protocol == "https")? https : http
var req = request.request(options, function(res){
var result = ""
console.log("STATUS: " + res.statusCode)
console.log("HEADERS: " + JSON.stringify(res.headers))
res.setEncoding("utf8")
res.setTimeout(50, null)
res.on("data", function(chunk){
result += chunk
})
res.on("end", function(){
console.log(result)
})
})
req.end()
}catch(err){
console.log(err.message)
}
}
I would like to know 2 things:
Why is getting the database connection causing this problem?
Why does it happen only on GET requests and not on POST and PUT?
Google and previous SO questions haven't been able to help so far.
Thanks.
The reason you are seeing the error is because you're placing request/response instances on the router itself. Don't do that. The router object is a "static" object, it's not a per-request thing. So currently this is what's happening (in order):
Request #1 comes in and sets req/res on router and starts the asynchronous model.create().
Meanwhile, request #2 comes in and overwrites req/res on router and starts its own asynchronous model.create().
Request #1's model.create() callback is called, sending the response to request #2's socket instead.
Request #2's model.create() callbacks is called, where it attempts to send a response to the same res that was just responded to just a moment ago. Trying to write headers to a response that has already been sent then results in the error you are seeing.