Nodejs Using domain.dispose() causes server to respond with status 0 - node.js

When I use domain.dispose() in Node.js expressjs based HTTP Server, the client making HTTP sees a response code of 0 (Could not get any response). If I remove domain.dispose() I receive 500 error with the desired error message. Below is my code
//Enable domains
app.use(function(req, res, next){
var createDomain = require('domain').create;
var domain = createDomain();
domain.add(req);
domain.add(res);
domain.run(function() {
next();
});
domain.on('error', function(e) {
//no further domain watch required
domain.dispose(); //if I remove this line status code of 500 is received on client, otherwise 0 or no response is received
next(e);
});
});
//Respond with 500 for Unhandled errors
app.use(function(err, req, res, next) {
// If the error object doesn't exists
if (!err) return next();
// Log it
req.log.error(err);
//console.error(err.stack);
try{
if(req.path && req.path.indexOf('/api/') === 0){
if(!res.headersSent){
console.log('responded with an error');
res.status(500).send({error: err.message});
console.log('responded with an error ACK');
}
return;
}
// Error page
res.status(500).render('500', {
error: err.stack
});
} catch(ex){
console.log('An error occured while responding 500');
req.log.error(ex);
}
});
Can anyone explain this or a better solution? Removing domain.dispose() may cause further exceptions, which may cause to re-enter the domain, and I do want to acknowledge client with the exception message as in my code.

This is expected behaviour of domains. Since you have explicitly added req and res to domain, so they are disposed as well. Don't use dispose, it does unexpected things. When you catch an error with domain the only sensible thing to do is to shutdown the process as quickly as possible.

Related

How to handle developer errors in Express.js?

I have to differentiate between operational and programmer(developer) errors. All errors with stack property are marked as developer errors. I log them and crash the server.
My question is if this approach will correctly identify all programmers errors (tried to read property of "undefined", called an asynchronous function without a callback, passed a "string" where an object or int was expected etc.)
Here is my error handler:
app.use((err, req, res, next) => {
// Delegate to the default Express error handler,
// when the headers have already been sent to the client
if (res.headersSent) return next(err);
// Decorate with additional properties from Boom
// If err has no specified status code or there is a stack, it is most likely a programmer error.
// Server must crash and restart. Default error code is set to 'Internal Server Error (500)'
const options = err.stack || !err.statusCode
? { data: { stack: err.stack || 'n/a', developerError: true } }
: {};
if (!err.isBoom) boom.boomify(err, options);
// Add more details
const message = {
...err,
originalUrl: req.originalUrl,
method: req.method,
ip: req.ip
};
// Log server errors only. No need to log 402, 403 etc.
if (err.isServer) winston.error(message);
// Crash server in case of a developer error.
// NOTE: a Node.js process manager should be set up to immediately restart the crashed server
// eslint-disable-next-line no-process-exit
if (err.data && err.data.developerError) process.exit(1);
return res.status(err.output.statusCode).json(message);
});

Node.js Express - provide HTTP response before finish processing entire request

I have a Node.js Express server where I send the response, and then attempt to do more processing with the same request instance.
If I write to res after headers are sent, I will get an error- but what happens if I use the req readable stream after I send back the response for the corresponding response?
In other words, how can I send an HTTP response with a Node.server before I finish processing the entire request?
In other other words, if I already have sent back a response, how can I "consume" the request after having already sent the response - is it really just a matter of doing anything besides send back a response?
Right now, there seem to be some weird errors related to using the request object (stream) that corresponds to the response that was already sent..
Let me give some examples, with code-
the following shows the last 3 Express middleware handlers in my server. As one interesting sidenote - once one middleware handler is invoked for a request, it can't be reinvoked (it appears so). So what happens is that the first handler below gets invoked when the response is sent. Then, the other path of execution (using process.nextTick or setImmediate) calls next(), and the second two handlers are invoked, which means I end up getting a 404 logged on my server.
app.use(function (req, res, next) {
var r;
var timeRequired = (Date.now() - req.request_start) + 'ms';
console.log("Time required for request:", timeRequired);
if (r = req.lectalTemp) {
if (!req.lectalSent) {
req.lectalSent = true;
res.status(r.status).json({timeRequired: timeRequired, success: r.data});
}
else {
console.log('Headers sent already, but here is the data that would have been sent:', r);
}
}
else {
next();
}
});
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('404: Not Found - ' + req.method + ' ' + req.originalUrl);
err.status = 404;
next(err);
});
app.use(function (err, req, res, next) {
var timeRequired = (Date.now() - req.request_start) + 'ms';
if (app.get('env') === 'production') {
res.status(err.status || 500).json({
error: 'sorry the API experienced an error serving your priority request'
});
}
else {
console.error(colors.bgRed(err), '\n', err.stack);
if (!res.headersSent && !req.lectalSent) {
req.lectalSent = true;
res.status(err.status || 500).json({
error: {
timeRequired: timeRequired,
errMessage: err.message,
errStack: err.stack
}
});
}
}
});
I would have solved this with a queue. Post a message with the low critical data to a queue (eq. RabbitMq or similar) and create a worker that consume the messages in the queue asynchronously.

Error handling in Node.js + Express using promises

Using Node.js + Express (4) + Mongoose (using promises rather than callbacks), I can’t sort out how to tidy up my error handling.
What I've got (rather simplified) is:
app.get('/xxx/:id', function(request, response) {
Xxx.findById(request.params.id).exec()
.then(function(xxx) {
if (xxx == null) throw Error('Xxx '+request.params.id+' not found');
response.send('Found xxx '+request.params.id);
})
.then(null, function(error) { // promise rejected
switch (error.name) {
case 'Error':
response.status(404).send(error.message); // xxx not found
break;
case 'CastError':
response.status(404).send('Invalid id '+request.params.id);
break;
default:
response.status(500).send(error.message);
break;
}
});
});
Here, in the switch in the ‘promise rejected’ section, the Error is the error I threw myself for a potentially valid id which is not found, the CastError is Cast to ObjectId failed thrown by Mongoose for an invalid id, and the 500 error can for instance be triggered by mistyping throw Error() as throw Err() (causing a ReferenceError: Err is not defined).
But like this, every one of my routes has this great big clumsy switch to handle the different errors.
How can I centralise the error handling? Can the switch be tucked away into some middleware somehow?
(I did hope I could just re-throw using throw error; within the 'promise rejected' block, but I haven’t been able to make it work).
I would create middleware to handle errors. Using next() for 404s. and next(err) for other errors.
app.get('/xxx/:id', function(req, res, next) {
Xxx.findById(req.params.id).exec()
.then(function(xxx) {
if (xxx == null) return next(); // Not found
return res.send('Found xxx '+request.params.id);
})
.then(null, function(err) {
return next(err);
});
});
404 handler
app.use(function(req, res) {
return res.send('404');
});
Error handler
app.use(function(err, req, res) {
switch (err.name) {
case 'CastError':
res.status(400); // Bad Request
return res.send('400');
default:
res.status(500); // Internal server error
return res.send('500');
}
});
You can improve upon this more by sending a json response like:
return res.json({
status: 'OK',
result: someResult
});
or
return res.json({
status: 'error',
message: err
});

NodeJS send xhr response to unavailable client

I have a http-function that responses on a request as usual:
app.post('/file', function(res, req){
write(req.body.file, function(err, id){
if(!err)
res.send({id:id});
else
{
res.status(500);
res.send({ error: 500 });
}
});
});
I post a file that is beeing written to the filesystem. When the file was written, I send a response back to the client. Now the client lost the connection to the internet, the server can't send the response, throws an error and gets killed.
Error:
Error: Request aborted
at IncomingMessage.onReqAborted ....
....
http.js:689
throw new Error('Can\'t set headers after they are sent.');
How can I catch this exception?
To catch those errors you can res.on('error', function(err) {}) or req.socket.on('error', function(err) {}) to catch lower-level errors, although I think the lower-level errors do bubble up to the request/response object also.
I should also point out that your route parameters are flipped, it should be (req, res), not (res, req).

How to send a custom http status message in node / express?

My node.js app is modeled like the express/examples/mvc app.
In a controller action I want to spit out a HTTP 400 status with a custom http message.
By default the http status message is "Bad Request":
HTTP/1.1 400 Bad Request
But I want to send
HTTP/1.1 400 Current password does not match
I tried various ways but none of them set the http status message to my custom message.
My current solution controller function looks like that:
exports.check = function( req, res) {
if( req.param( 'val')!=='testme') {
res.writeHead( 400, 'Current password does not match', {'content-type' : 'text/plain'});
res.end( 'Current value does not match');
return;
}
// ...
}
Everything works fine but ... it seems not the the right way to do it.
Is there any better way to set the http status message using express ?
None of the existing answers accomplish what the OP originally asked for, which is to override the default Reason-Phrase (the text appearing immediately after the status code) sent by Express.
What you want is res.statusMessage. This is not part of Express, it's a property of the underlying http.Response object in Node.js 0.11+.
You can use it like this (tested in Express 4.x):
function(req, res) {
res.statusMessage = "Current password does not match";
res.status(400).end();
}
Then use curl to verify that it works:
$ curl -i -s http://localhost:3100/
HTTP/1.1 400 Current password does not match
X-Powered-By: Express
Date: Fri, 08 Apr 2016 19:04:35 GMT
Connection: keep-alive
Content-Length: 0
You can check this res.send(400, 'Current password does not match')
Look express 3.x docs for details
UPDATE for Expressjs 4.x
Use this way (look express 4.x docs):
res.status(400).send('Current password does not match');
// or
res.status(400);
res.send('Current password does not match');
You can use it like this
return res.status(400).json({'error':'User already exists.'});
One elegant way to handle custom errors like this in express is:
function errorHandler(err, req, res, next) {
var code = err.code;
var message = err.message;
res.writeHead(code, message, {'content-type' : 'text/plain'});
res.end(message);
}
(you can also use express' built-in express.errorHandler for this)
Then in your middleware, before your routes:
app.use(errorHandler);
Then where you want to create the error 'Current password does not match':
function checkPassword(req, res, next) {
// check password, fails:
var err = new Error('Current password does not match');
err.code = 400;
// forward control on to the next registered error handler:
return next(err);
}
At server side(Express middleware):
if(err) return res.status(500).end('User already exists.');
Handle at Client side
Angular:-
$http().....
.error(function(data, status) {
console.error('Repos error', status, data);//"Repos error" 500 "User already exists."
});
jQuery:-
$.ajax({
type: "post",
url: url,
success: function (data, text) {
},
error: function (request, status, error) {
alert(request.responseText);
}
});
When using Axios you can retrieve the custom response message with:
Axios.get(“your_url”)
.then(data => {
... do something
}.catch( err => {
console.log(err.response.data) // you want this
})
...after setting it in Express as:
res.status(400).send(“your custom message”)
My use-case is sending a custom JSON error message, since I'm using express to power my REST API. I think this is a fairly common scenario, so will focus on that in my answer.
Short Version:
Express Error Handling
Define error-handling middleware like other middleware, except with
four arguments instead of three, specifically with the signature (err,
req, res, next). ... You define error-handling middleware last, after
other app.use() and routes calls
app.use(function(err, req, res, next) {
if (err instanceof JSONError) {
res.status(err.status).json({
status: err.status,
message: err.message
});
} else {
next(err);
}
});
Raise errors from any point in the code by doing:
var JSONError = require('./JSONError');
var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);
Long Version
The canonical way of throwing errors is:
var err = new Error("Uh oh! Can't find something");
err.status = 404;
next(err)
By default, Express handles this by neatly packaging it as a HTTP Response with code 404, and body consisting of the message string appended with a stack trace.
This doesn't work for me when I'm using Express as a REST server, for example. I'll want the error to be sent back as JSON, not as HTML. I'll also definitely not want my stack trace moving out to my client.
I can send JSON as a response using req.json(), eg. something like req.json({ status: 404, message: 'Uh oh! Can't find something'}). Optionally, I can set the status code using req.status(). Combining the two:
req.status(404).json({ status: 404, message: 'Uh oh! Can't find something'});
This works like a charm. That said, I find it quite unwieldy to type every time I have an error, and the code is no longer self-documenting like our next(err) was. It looks far too similar to how a normal (i.e, valid) response JSON is sent. Further, any errors thrown by the canonical approach still result in HTML output.
This is where Express' error handling middleware comes in. As part of my routes, I define:
app.use(function(err, req, res, next) {
console.log('Someone tried to throw an error response');
});
I also subclass Error into a custom JSONError class:
JSONError = function (status, message) {
Error.prototype.constructor.call(this, status + ': ' + message);
this.status = status;
this.message = message;
};
JSONError.prototype = Object.create(Error);
JSONError.prototype.constructor = JSONError;
Now, when I want to throw an Error in the code, I do:
var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);
Going back to the custom error handling middleware, I modify it to:
app.use(function(err, req, res, next) {
if (err instanceof JSONError) {
res.status(err.status).json({
status: err.status,
message: err.message
});
} else {
next(err);
}
}
Subclassing Error into JSONError is important, as I suspect Express does an instanceof Error check on the first parameter passed to a next() to determine if a normal handler or an error handler must be invoked. I can remove the instanceof JSONError check and make minor modifications to ensure unexpected errors (such as a crash) also return a JSON response.
If your goal is just to reduce it to a single/simple line, you could rely on defaults a bit...
return res.end(res.writeHead(400, 'Current password does not match'));
Well in the case of Restify we should use sendRaw() method
Syntax is:
res.sendRaw(200, 'Operation was Successful', <some Header Data> or null)

Resources