I'm running a Restful API Server based on Node.js using Express.js.
Today, I realized that someone can get information of error of my source code, including directory path of my server, when he send request using Curl like curl -X POST ~.
Error message I get:
TypeError: Cannot read property 'text' of undefined
at exports.list (/usr/local/node/XXX/routes/message.js:49:36)
at callbacks (/usr/local/node/XXX/node_modules/express/lib/router/index.js:124:37)
at param (/usr/local/node/XXX/node_modules/express/lib/router/index.js:118:11)
at param (/usr/local/node/XXXv/node_modules/express/lib/router/index.js:125:11)
How can I hide those critical information when the server displays errors?
I'd set the NODE_ENV flag to production, as the Express.JS doesn't send the stack data in this mode. I recommend you to check out the dotenv module in npm.
If you pass an error to next() and you do not handle it in a custom error handler, it will be handled by the built-in error handler; the error will be written to the client with the stack trace. The stack trace is not included in the production environment.
https://expressjs.com/en/guide/error-handling.html
Set your environment variable NODE_ENV to production when running Node.js to suppress stack traces. It’ll still be shown on the console.
You can create a middleware that deals with all unhandled errors for you.
app.use((err, req, res, next) => {
if (err) {
return res.sendStatus(500);
}
next();
});
That will return a 500 Internal Server Error status code to any user creating such an error. Remember to put this at the end of your middleware chain.
Just send them this kind of response if you don't want to send any message
res.sendStatus(500);
or you can use errorhandler in your express setting like this if you want to send stacktrace as well
var errorHandler = require('errorhandler');
.....//define app as express object
if (process.env.NODE_ENV === 'development') {
// only use in development
app.use(errorhandler())
}
Related
let's take this snippet for example
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
app.use(bodyParser.urlencoded({ extended: false }))
app.get(...)
# all my routes #
app.use(function (err, req, res, next) {
console.error(err.stack)
res.status(500).send('Something broke!')
})
app.listen(9000)
....
if body-parser throws an error?
Maybe the client closes the connection or the request payload is too large
the client will receive an error with status code 500 from the default express error handler but it’s probably a error that should return 4xx response .
I thought of putting a middleware right after it and calling res.send with the error and status code 400.
maybe wrap all my 3rd party middle ware with try-catch handler
Or adding in my error handler middleware a huge switch case
And over time adding error thrown from middleware third party middleware and change there status code to 400
All the solutions not really bolt proof and need maintenance over time
What us the best practice any suggestions?
The body-parser module should call next(err) when it encounters an error and you can then intercept that by providing an Express error handler such as:
app.use(function(err, req, res, next) {
console.error(err.stack)
res.status(500).send('Put your content here')
});
When you define this special middleware (with four arguments), then Express will keep track of that separately as an error handler that should be called when/if some request handler calls next(err) or if a synchronous exception is caught by Express.
Express has a default error handler if you do not provide one which you can read about here. But, if you supply one, then yours will take over and you can do whatever you want from the error handler. You can even just log the error and take the user to an error page - you don't have to even send an http error status if it's a web page request. If it's an API, you should probably be using http error statuses.
what is the best practice?
Best practice is to include your own Express error handler where you will be able to intercept all errors that are sent on to next(err).
I thought of putting a middleware right after it and calling res.send with the error and status code 400 or maybe wrap all my 3rd party middle ware with try-catch handler
Your third party middleware needs to behave properly in the Express eco-system. That means that it can throw synchronously and Express will catch it automatically and send to the Express error handler. The code should not throw asynchronously (as is true for all types of code) because nobody can catch those exceptions (unless they are in promise-structured code). You shouldn't have to wrap middleware yourself.
Internal errors should generally not be 4xx errors, but rather 5xx errors. Whether or not you surface an internal error back to the end user depends entirely upon the context. Usually, the user will be shown some sort of general purpose error page. Or, if it's an API, the API will have a scheme for communicating errors and typically the API will return actual http status codes that appropriately map to the type of problem.
after further investigation, this is the best solution suited for me
simply adding another middleware after body parse
https://www.npmjs.com/package/express-body-parser-error-handler
I want to have a system which will either send me a text message or email based on severity of error on respective occurrence. I have done some research on the subject but I haven't been able to simplify matters.
All in all my end goal is to get notification whenever something is going wrong with my production server. In case of serious issues which are not caught at all I have used process's uncaughtException and for specific routes which are called via separate API calls I can simply use try catch blocks.
My first issue is I cannot handle errors thrown from different routes directly via my main server file.
Second is I'll have to write same kinda' code in every route for exception handling. If something could just listen to all the errors from main server file then I can do things easily.
You can use an error handling middleware in Express:
app.use(function (err, req, res, next) {
console.error(err.stack);
// do whatever you need to send a notification
res.status(500).send('Internal error');
});
See the documentation on the error handling in Express:
https://expressjs.com/en/guide/error-handling.html
Everything you ask about is explained very well there.
How do you pass nice error messages to clients in express?
app.use(errorHandler);
function errorHandler(err, req, res, next) {
res.send(err);
}
app.post('/login', usernameIsValid, pwdIsValid, createToken);
In usernameIsValid I create a new Error with a message and status and call next(err). Now this bypasses pwdIsValid and createToken like it should BUT the weird thing is my errorHandler logs the error without a console.log. Am I using the default error handler in express somewhere? How do I turn it off? I have tried both production and development for NODE_ENV.
On the client xhr.responseText is my error.message + what looks like a stack trace? I've even tried just to send err.message but it looks the same.
One way to handle this mess is to make each middleware (if there is an error) create an error string like req.data.err = "invalid username" and then make sure each following middleware checks req.data.err if the string is present. But this is tedious as hell >_<
I solved it. You need to apply the error handler app.use(errorHandler) dead last after all other routes. This disables the built-in error handler. Now you may pass pretty error messages to the client.
Read more here.
edit: process.env.NODE_ENV does not matter.
From the express documentation site
If you pass an error to next() and you do not handle it in an error handler, it will be handled by the built-in error handler; the error will be written to the client with the stack trace. The stack trace is not included in the production environment.
So if you want to avoid the stacktrace you only need to execute your application with the NODE_ENV set to production.
Run you application as follows:
$ NODE_ENV=production node file.js
everytime I have a critical error which terminates the server on NodeJS which comes from a request of a client, he gets the error dump.
How can I change this behaviour ?
I assume you are talking about Express.js. Error stack trace is sent to client when environment is not production (please refer Express docs).
To disable this behavior, you should set NODE_ENV environmental variable
to production.
You can process the error - more common is 404 and 500.
Follow one example to do this (in case express):
exports.notFound = function(req, res, next) {
res.status(404);
res.render('not-found');
};
exports.serverError = function(error, req, res, next) {
res.status(500);
res.render('server-error', {error: error});
};
And create the files not-found and server-error (EJS or Jade for example) for show custom page in case of error.
So when a login fails to validate, I currently respong with res.send(401). However I want to send a snippet of text or html along with the error code.
I tried this:
res.write('string');
res.send(401);
but threw an error and my server wouldn't start.
You're mixing Express methods with the native HTTP methods. Since Express' internally uses the native HTTP modules, you should use one or the other.
// Express
res.status(401);
res.send('string');
// or the shortcut method
res.send(401, 'string');
// HTTP
res.writeHead(401);
res.end('string');
From the examples in express docs
res.status(404).send('Sorry, we cannot find that!');
res.status(500).send({ error: 'something blew up' });
A bit more verbose example, but works even when you try to render a template:
res.status(401).send('Unauthorized')
or
res.status(401).render('/401.html')
res.send(error_code,msg);
is deprecated. You should do this instead.
res.status(error_code).send(msg);
Update:
For express v 4.13.4, it will throw error when you do this.
res.status(error_code).send(msg);
saying you can't set headers after they are sent.