I build a server with node.js and Express.
Everything works great, but in some cases the client sends invalid parameter, that I don't predict, and I don't handle with. The result of these requests that my server failed, and can't serve other requests.
For example, In one of my function. I have the next lines:
app.post("/getFile", function (req,res){
// some code...
fs.read(fd, buffer, 0, byteRoRead, start, function(err, bytesRead, buffer){
buffer.pipe(res);
})
})
Because the client sent incorrect start param, my server failed with the next error:
fs.js:457
binding.read(fd, buffer, offset, length, position, wrapper);
^
Error: Offset is out of bounds
So now I can fix it, but there is many other error that I can't predict, so I want to gives a client response of unexpected error, but I want that my server would still alive.
Express has built in error handling as a middleware. See http://expressjs.com/guide.html#error-handling for a more comprehensive guide but as an example:
app.use(function(err, req, res, next){
console.error(err.stack);
res.send(500, 'Something broke!');
});
This middleware would catch the error, log it to the console and return a 500 page to the user. This also will stop the server crashing. If you wanted to log the error, but still let the server crash add throw err; to the body of that function.
This is sometimes a good idea as you may not want the server to continue to serve requests if it is in some unexpected error state. Refer to http://shapeshed.com/uncaught-exceptions-in-node/ as a good brief guide on the subject. Also, see http://www.joyent.com/developers/node/design/errors for a more detailed discussion.
Related
I have some proxy code like this below. Problem is that whenever the target server is down, this code fails to capture the error, resulting in the entire application crashing with Error: connect ECONNREFUSED.
For a proxy server, this is terrible, it needs to just return an error to the caller, not crash altogether upon the first time that the target server is unreachable.
What is the right way around it these days?
Node version 6.
let targetUrl = "http://foo.com/bar"
app.options('/cors-proxy/bar', cors())
app.post('/cors-proxy/bar', function(req, res) {
console.log(`received message with method ${req.method} and some body ${req.body}`)
console.log(`relaying message to ${targetUrl}`)
try {
req.pipe(
request({
url: targetUrl,
method: req.method,
json: req.body
})
).pipe(res);
} catch (err) {
res.status(502)
res.render('error', {
message: err.message,
error: err
});
}
});
Thanks!
In general, you can't use try/catch to catch exceptions that may occur in asynchronous callbacks or asynchronous operations. That will only catch synchronous errors.
Instead, you have to read how each particular asynchronous operation reports errors and make sure you are plugged into that particular mechanism.
For example, streams report errors with a message to the stream that you intercept with stream.on('error', ...). For example, a request() can report errors several different ways depending upon which request() library you are actually using and how you are using it.
Some references:
Error handling with node.js streams
Stream Readable Error
How Error Events Affect Piped Streams in Node.js
I'm working on an api in Node.js and learned about an option to give my errors one last look before crashing my app...(uncaughtException)
Note: I'm well read at this point on all the reasons some people don't like this feature, so please don't post those concerns here.
The problem I'm experiencing is this:
I create custom error classes for different pieces of code. for instance a Redis_Exception, which will get thrown in response to errors in my cache layer.
However the following does not bubble up to my uncaughtException function:
throw new Redis_Exception('Some error here');
Instead my app simply prints Redis_Exception: Some error here to the console. No stack trace as per usual.
Is there some reason that errors thrown in this manner would not bubble up to the top of my applications process?
An easier way around it, add a middleware with your express server with 4 arguments, 1st argument being the error. This will override the finalhandler handler.
app.use((err, req, res, next) => {
// Similar to uncaughtException handler
// Log error, maybe send it to central server
// Send Custom Log message maybe?
return res.send('Nice server error to user');
}
You should also still keep process.on('uncaughtException', fn); to handle any uncaught exceptions outside of the http request response pipeline.
Figured out what it is. For some reason express has decided to handle my errors for me.
In this file /node_modules/finalhandler/index.js on line 67 they basically handle any unhandled errors, which keeps uncaughtErrors from bubbling up to the top of the stack...or down to the bottom. Not really sure which direction this thing is facing.. :D
I added a line to that file and errors starting going through to my exception handler:
66 // unhandled error
67 if (err) {
68 throw err; //my line
I'm not sure how i'm going to move forward knowing this as I don't want to overwrite core functionality, but I'm armed with knowledge now.
UPDATE: After opening tickets with finalhandler and express I got back some info on how to override the default functionality.
The tickets I opened are:
https://github.com/pillarjs/finalhandler/issues/6
https://github.com/strongloop/express/issues/2707
Basically if you wrap your app object in a new http server you can override the last event with your own final function.
var express = require('express')
var http = require('http')
var app = express()
// declare things on app
var server = http.createServer(function (req, res) {
app(req, res, function (err) {
// this is your replacement for finalhandler
})
})
server.listen(3000)
In our restify app, when we pass an error to next, a generic 500 error is returned, which is all just fine. However, I need to also log the details of the error somewhere so that I know what happened.
Previously, I worked on an express application, and a centralized error-handling middleware gave us the ability to do any arbitrary code when receiving errors, like logging.
What's the "restify way" to centralizing the logging of error details? I do not want to sprinkle logging statements throughout the entire app.
A Restify server object emits an 'after' event once all other route handlers are done for a request. You can put your logging code in an 'after' event handler:
var svr = restify.createServer()
.get('/hello-world', hello_world_hndlr)
.on('after', function (req, resp, route, err) {
// logging here
})
.listen(SVR_PORT)
An alternative to listening to 'after' is listening to 'restifyError':
server.on('restifyError', (req, res, err, cb) => {
req.log.error(err)
return cb();
});
app.get('/', function(req, res) {
doSomethingAsync(function(err) {
throw new Error('some unexpected/uncaught async exception is thrown');
})
})
Possibly unhandled Error: some unexpected/uncaught async exception is thrown
at ...stacktrace...:95:9
From previous event:
at ...stacktrace...:82:6)
at ...stacktrace...:47:6)
at ...stacktrace...:94:18)
I have tried a bunch of domain middlewares however they all only work for express 3. I am currently on express 4.5 and I am wondering if express had changed that domain no longer works.
Currently, when an exception is thrown, the response basically hangs until a timeout.
assume the error you got is inside router or controller
put this in very end of your app configuration, before listening
app.use(function(err, req, res) {
res.status(err.status || 500);
// if you using view enggine
res.render('error', {
message: err.message,
error: {}
});
// or you can use res.send();
});
your app will catch any uncaught router error and will render "error" page
by the way do not forget to include "next" in your router Initialization
Edited
app.get('/', function(req, res, next) {
try {
signin(req.query.username, req.query.password, function(d){
if (d.success) {
req.session.user = d.data;
}
res.end(JSON.stringify(d));
});
} catch(e) {
next(e);
}
}
Hope it help
As you have found, trying to try/catch an asynchronous function doesn't work. Domains should work just fine in express 4 (or express 3, or straight http, whatever). I've never used any express middleware that attempts to implement domain handling though, so I can't really speak to how well they do or don't work.
I'd suggest just implementing domain handling on your own; it's not that bad. One of the better examples of using domains is right in node's documentation on domains (not the first bad example they show, the second, good one). I strongly recommend reading those docs.
The basic idea is pretty simple:
Create a domain
Add an error handler
Call domain.run(function() { ... }) putting the code you want inside the domain in that run callback.
An extremely simple (and very localized) example:
// This will alwas throw an error after 100ms, but it will still
// nicely return a 500 status code in the response.
app.get('/', function(req, res) {
var d = domain.create();
d.on('error', function(err) {
res.status(500).send(err.message);
});
d.run(function() {
setTimeout(function() {
throw new Error("some unexpected/uncaught async exception");
}, 100);
});
});
So, that will work and it might be enough for your case, but it's not the best solution (If you've read the docs, you might notice that it's pretty darn close to their bad example). The problem is (from the docs again):
By the very nature of how throw works in JavaScript, there is almost
never any way to safely "pick up where you left off", without leaking
references, or creating some other sort of undefined brittle state.
The best solution (as far as I'm aware anyway) is to do what's recommended in the node docs. The basic idea that they suggest is to use cluster (or something similar) to start multiple worker processes which run your web server from a master process. In each of those worker processes, setup a domain which will nicely send back a 500 status when an error is thrown and then exit. Then, in the master process, detect when a worker exits and simply start up a new one.
What that does is eliminate any problems with "picking up where you left off" by simply restarting the entire process when there's a thrown error, but only after handling it gracefully.
Putting an example of that in a SO answer is probably a bit much, but there really is a great example right in the node docs. If you haven't already, go take a look at it. :)
I build a server which get many requests and response to them.
In some cases, there is an error which cause the server to crush:
events.js:72
throw er; // Unhandled 'error' event
^
Error: ENOENT, open '/mnt/ace/0/file'
I have two problems:
the stack trace doesn't give me any information about the line in my application that cause this exception (I can't do manually debugging because it happens just when I get 1000 request or more).
I don't want that my server ould crush. I prefer that it will raise an exception, but will continue to work.
What the best implementation for this?
You can listen for that kind of stuff and not have it crash the app, but that's not always a great idea.
process.on('uncaughtException', function(err) {
console.log('Something bad happened');
console.log(err.stack);
});
In your case, have you tried checking ulimit settings? You may be having problems opening file handles under loads of 1000+.
Another way of thinking about this is to use domains (if you're using >= 0.8). Domains give you a finer grain of control over how you handle errors based on what contexts cause them.
var domain = require('domain').create();
domain.on('error', function(err) {
console.log(err);
});
domain.run(function() {
// Your code that might throw
});