I have been trying different error handling techniques with Express. First I was just using process.on('uncaughtException'). I quickly learned that it was bad practice. After that, I tried using the new "Domain" feature in node js. I wrapped each request in a domain, however, if I would send a response and then do some more work on the server (dealing with the same request) it would not catch the errors from those functions after the response was sent. I then tried moving to the built-in error handling with Express using next(err). However, I am running into the same situation. If I send a response and then a function has an error after the response has been sent, my error handler is not called. Here is some code as an example.
async.waterfall([
function(after)
{
hashPassword(password, after);
},
function(hash, after)
{
makeToken(hash, after);
},
function(hash, token, after)
{
insertUserInfo(email, username, hash, ip, token, after);
},
function(token, id, after)
{
req.session.attempts = 0;
res.json({ err: 0, attempts: 0 }); //Response is sent
after(null, token, id);
},
function(token, id, after)
{
sendEmail(token, email, renderEmail); //Errors not caught
makeFolder(id, after); //Errors not caught
}
], function(err) {
if(err)
next(err);
}
);
As you can see from the code, I am registering a new user. Now, I could wait until I have completed all of my logic to send back the response but I thought that it would make the request appear much faster for the user if I did some of the less important things after the response has been sent. I am willing to change my code to perform everything THEN send the response, but I want to make sure that there is no solution out there that I have not tried yet.
As awesome as Express JS is, it doesn't have a time travel feature allowing you to unsend a request :) This is really the root of your problem. If your response must display the outcome, then it must wait until all the relevant actions to complete.
Related
I've got a small Express JS api that I'm building to handle and process multiple incoming requests from the browser and am having some trouble figuring out the best approach to handle them.
The use case is that there's a form, with potentially up-to 30 or so people submitting form data to the Express JS api at any given time, the API then POSTS this data of to some place using axios, and each one needs to return a response back to the browser of the person that submitted the data, my endpoint so far is:
app.post('/api/process', (req, res) => {
if (!req.body) {
res.status(400).send({ code: 400, success: false, message: "No data was submitted" })
return
}
const application = req.body.Application
axios.post('https://example.com/api/endpoint', application)
.then(response => {
res.status(200).send({ code: 200, success: true, message: response })
})
.catch(error => {
res.status(200).send({ code: 200, success: false, message: error })
});
})
If John and James submit form data from different browsers to my Express JS api, which is forwarded to another api, I need the respective responses to go back to the respective browsers...
Let's make clear for you, A response of a request will only send to the requester, But if you need to send a process request and send a response like, hey i received your request and you can use another get route to get the result sometimes later, then you need to determine which job you mean. So You can generate a UUID when server receives a process request and send it back to the sender as response, Hey i received your process request, you can check the result of process sometimes later and this UUID is your reference code. Then you need to pass the UUID code as GETparam or query param and server send you the correct result.
This is the usual way when you are usinf WebSockettoo. send a process req to server and server sends back a reference UUID code, sometime later server sends the process result to websocket of requester and says Hey this is the result of that process with that UUID reference code.
I hope i said clear enough.
I am new to Node.js and i am trying to refresh the data periodically using the below code:
router.post('/getMessage',function(req,res){
setInterval(findMessage,5000);
function findMessage() {
Message.find(
{
$or: [
{sender: req.body.sender, receiver: req.body.receiver},
{sender: req.body.receiver, receiver: req.body.sender}
]
},
(err, data) => {
res.send({success: true, data: data});
}
);
}
});
But this gives an error: "Cannot set headers after they are sent". I understand that res.send calls res.end() implicitly and therefore this error is occuring. And have tried res.write() also. But i am returning an object and not a String or buffer, hence it also failed to work.
It would be great if someone could give an example of how to achieve this exactly.
response.send() method does two task
1. write content on the response and send.
2. End connection with res.end().
So, when you did response.send(), then it sends your message and closes the connection. For that reason, you getting the error "Cannot set headers after they are sent".
So, the conclusion is that you can't send multiple responses using response.send().
You can achieve this by the socket.io or you can make the request from frontend after an interval.
I'm trying to serve 500 pages (some generic HTML that says "500 - internal server error") from my Node.js server to requests that failed to resolve due to developer bugs, but can't find an elegant way to do this.
Lets say we have the following index.js, where a developer innocently made a mistake:
const http = require('http');
const port = 12345;
http.createServer(onHttpRequest).listen(port);
function onHttpRequest(req, res) {
var a = null;
var b = a.c; // this is the mistake
res.end('status: 200');
}
Trying to access property "c" of null throws an error, so "res.end" will never be reached. As a result, the requesting client will eventually get a timeout. Ideally, I my server to have code that can catch errors like this, and return 500 pages to the requesting client (as well as email an administrator and so on).
Using "try catch" in every single block is out of the question. Most Node.js code is async, and a lot of the code relies on external libraries with questionable error handling. Even if I use try-catch everywhere, there's a chance that an error would happen in an external library that didn't have a try-catch block inside of it, in a function that happens asynchronously, and thus my server will crash and the client would never get a response.
Shortest example I can provide:
/* my server's index.js */
const http = require('http');
const poorlyTestedNpmModule = require('some-npm-module');
const port = 12345;
http.createServer(onHttpRequest).listen(port);
function onHttpRequest(req, res) {
try {
poorlyTestedNpmModule(null, onResult);
}
catch(err) {
res.end('status: 500');
}
function onResult(err, expectedResult) {
if(err) {
res.end('status: 400');
}
else {
res.end('status: 200');
}
}
}
/* some-npm-module.js */
module.exports = function poorlyTestedNpmModule(options, callback) {
setTimeout(afterSomething, 100);
function afterSomething() {
var someValue = options.key; // here's the problem
callback(null, someValue);
}
}
Here, the server crashes, due to a function call that led to code that asynchronously throws an error. This code is not code that I control or wish to modify; I want my server to be able to handle all those errors on its own.
Now, I could, for instance, just use the global uncaughtException event, i.e.:
process.on('uncaughtException', doSomething);
but then I have no access to the (req, res) arguments, making it impossible to call res.end for the correct res instance; the only way to have access to them, is to store them in a higher-scope object for each incoming request, and then prune them on successful request resolutions, then mark existing [req, res] stored pairs as "potentially errored" whenever an uncaughtException triggers, and serve 500 pages to those requests whenever the count of currently-active requests matches the count of currently-unresolved-errors (and re-test that count per thrown uncaught expection and per successful res.end call).
Doing that works, but... it's ugly as hell. It means that request objects have to be leaked to the global scope, and it also means that my router module now has a dependency on the uncaughtException global event, and if any other code overwrites that event, everything breaks, or if I ever want to handle other uncaught exceptions for whatever reason, I'll run into cross dependency hell.
The root cause of this problem is that an unexpected error can happen anywhere, but I want to specifically catch whether an unexpected error originated from a stack trace that began from an incoming http request (and not, for example, from some interval I have running in the background, because then I get an unexpected error but obviously don't want to serve a 500 page to anyone, only email an admin with an error log), and on top of needing to know whether the error originated from an http request, I need to have access to the request+response objects that node server objects provide.
Is there no better way?
[Edit] The topic of this question is role distribution in modules.
i.e., one guy is making base code for a server, lets say a "router module". Other people will add new code to the server in the future, handling branches that are routed to.
The guy that writes the base server code has to write it in a way that it will serve 500 pages if any future code is written incorrectly and throws errors. Help him accomplish his goal.
Answers of the format "make sure all future people that add code never make mistakes and always write code that won't throw uncaught errors" will not be accepted.
At first, using uncaughtException in Nodejs is not safe. If you feel that there is no other option in your application, make sure that you exit the process in the handler of 'uncaughtException' and restart the process using pm2 or forever or someother modules. Below link can provide you its reference.
Catch all uncaughtException for Node js app
Coming to the process of error handling, as mentioned, you may always miss to handle errors with callback. To avoid, these we can use an exceptional advantage of promises in nodejs.
/* my server's index.js */
const http = require('http');
const poorlyTestedNpmModule = require('some-npm-module');
const port = 12345;
http.createServer(onHttpRequest).listen(port);
function onHttpRequest(req, res) {
try {
poorlyTestedNpmModule(null)
.then(result => {
res.end('status: 200');
})
.catch(err =>{
console.log('err is', err);
res.end('status: 400');
})
}
catch(err) {
res.end('status: 500');
}
}
/* some-npm-module.js */
module.exports = function poorlyTestedNpmModule(options, callback) {
setTimeout(afterSomething, 100);
afterSomthing = new Promise((resolve, reject)=> {
var someValue = options.key; // here's the problem
resolve(someValue);
})
}
If you see that some of the npm nodemodules are not present with promise, try to write wrappers to convert callback to promise model and use them in your application.
To make a long story short:
I'm building node app which making a request with https (the secure version of http). Whenever I miss-configure my request options, I'm having this error:
Node.js Hostname/IP doesn't match certificate's altnames
Great... except of the fact that the entire request code is wrapped with a valid try..catch block (which works just fine.. checked that already). The code is basically something like this:
try
{
https.request(options, (response) =>
{
// no way I making it so far this that error
}).end();
}
catch(ex)
{
// for some reason.. I'm not able to get here either
}
What I intend to do is to simply handle that error within my try..catch block
After reading some posts I've learned that this behavior is mainly because the tls module is automatically process the request and therefore making this error - this is a nice piece of information but it doesn't really help me to handle the exception.
Some other suggested to use this option:
rejectUnauthorized: false // BEWARE: security hazard!
But I rather not... so.. I guess my questions are:
Handling an error with a try..catch block should work here..right?
If not - is this behavior is by-design in node?
Can I wrap the code in any other way to handle this error?
Just to be clear - I'm not using any third-party lib (so there is no one to blame)
Any kind of help will be appreciated
Thanks
You need to add an 'error' event handler on the request object returned by https.request() to handle that kind of error. For example:
var req = https.request(options, (response) => {
// ...
});
req.on('error', (err) => {
console.log('request error', err);
});
req.end();
See this section in the node.js documentation about errors for more information.
I'm having trouble to understand why my callback function needs 2 parameters, i.e. one for the request and one for the response?
For instance i bind a callback function to my server:
server.on("request", doThis(req, resp));
In my opinion he needs only one parameter (req for example here) to store the req information (GET, POST, url, etc.). Why does he need a second for response? I write the information in resp. (i.e. the server, so my other scripts) and not the client.
Every time a request is coming in, the callback function is invoked and so the req parameter is set. Am i wrong? But why do I need the response parameter? My server needs it when he is responding but not when I'm reading/saving the request informations?
The Response parameter is what's generally used to send back a response.
A request comes in, you get the request's data in the req (first) param and you then use the res (second) param to send back a response like:
server.on('message', function(req, res){
res.send('hello your ip is: ' + req.client.ip);
})
This is all dependant on your framework but in expressjs this is how it works (more or less).
To answer your question, you don't need it - you can simply not issue it as a parameter (although it will still be accessible) if you don't plan on responding (which is weird and quite uncommon)
server.on('message', function(req){
console.log('someone requested "message"')
})
Generally speaking, you would always send back a response although the end user might never visually see it, it's just to confirm that the action has been completed successfully.
server.on('save', function(req, res){
saveFile(req.file)
res.sendStatus(200)
})
Additionally, you could check if the process completed successfully - if it did you'd send back a success message, otherwise send back an error message.
server.on('save', function(req, res){
saveFile(req.file, function(error){
if(error) res.sendStatus(500)
res.sendStatus(200)
})
})