I've got a fairly standard connect-mongo setup
mongoose is initialised / connected prior to this
app.use(express.session({
secret: "sfdgsdgsdfg",
store: new MongoSessionStore({db: mongoose.connection.db})
}));
This works fine.
However -
Assuming my mongodb connection suddenly dies (stop mongod locally in the example below)
- the next time I try to hit a route, my express app crashes too -
Error: failed to connect to [localhost:27017]
at null. (/Users/alex/Projects/MyProject/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:540:74)
at emit (events.js:106:17)
at null. (/Users/alex/Projects/MyProject/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection_pool.js:140:15)
at emit (events.js:98:17)
at Socket. (/Users/alex/Projects/MyProject/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection.js:478:10)
at Socket.emit (events.js:95:17)
at net.js:440:14
at process._tickCallback (node.js:419:13)
Is there a way to handle this error and (For example) redirect to a /error route?
(Obviously one that doesn't require session!)
EDIT
So now, I'm creating a separate mongoose connection.
I then use the on('error' to listen for errors
...this is where I'm getting stuck -
The process still dies because re-throwing the err doesn't pass it into the express error handler...
var sessionDbConnection = mongoose.createConnection(config.sessionDb);
sessionDbConnection.on('error', function(err) {
console.log('oops');
throw err; //instead of re-throwing the error, i think i need to pass it to the error handler below??
})
app.use(express.session({
secret: "sfdgsdgsdfg",
store: new MongoSessionStore({db: sessionDbConnection.db})
}));
app.use(function(err, req, res, next) {
res.render('error', err); //just for testing
});
Setup a general error handler at the end of your using chain ...
//function must accept 4 arguments
app.use(function(err, req, res, next) {
//use accepts to determin if you should return json, html, image?
//render the appropriate output.
});
Also, have your handlers and other modules accept three parameters (req, res, next) in the case of an error, return next(err) typically you will want to optionally use a .code property to match up your http response code to the one matching the error. using 4xx for input errors, 5xx for server errors etc.
Also, if you want to handle the general case...
process.on('uncaughtException', function(err) {
console.error('Caught exception: ' + err);
console.error(err.stack);
//interrogate the error, if it's something you can recover from, let it be.
//if the exception is fatal, exit with prejudice
setTimeout(process.exit.bind(process, 666), 1000); //exit in a second
});
This will handle your specific case, but you should only allow the process to keep running if its' something that should recover on its' own.
In response to your edit... you could have a global variable that changes when you get a DB error... unfortunately, this error doesn't necessarily happen in the context of an http request.. it could happen before/during/after ... in this way, you cannot know.
If you are using a client that will re-connect on failure, then that will alleviate some issues. The best you can do, is keep track of this variable, serve errors to all requests.. then restart your process.
There are lots of modules from pm2 to forever that will help you with this.
Related
I log all 404s on my website. I keep getting them for pages I haven't linked to, and it's clearly someone (a bot) trying to find admin pages / secure files on my site such as /wp-admin.php;
router.get('/wp-admin.php', function(req, res, next) {});
I tried this and it doesn't seem to hold up the server, it just outputs something like this a minute later:
GET /wp-admin.php - - ms - -
Is there any detriment to adding routes such as that, where no response is sent, possibly wasting their time?
router.get('/wp-admin.php', function(req, res, next) {});
This will cause express to time out and close the connection. This will make Denial of Service attack easier for hackers and jam up your node server.
You can always use some kind of rate limiters to prevent continuous request from a certain IP.
express-rate-limit
is a can be used for this. It is simple express middleware
As noted in the already accepted answer, an Express route like that will leave you vulnerable.
I recommend going one step further and tearing down those requests using req.destroy.
I'm not sure of the implications of Express being included, here, though. For example, is the request body being read automatically by a middleware upstream of this request handler you've shown? If so, that would be an attack vector that makes the mitigation I'm suggesting useless.
Regardless, to demonstrate what I am suggesting with a vanilla HTTP server:
var h = require('http')
h.createServer(function(req, res) {
// tear down the socket as soon as the request event is emitted
req.destroy()
}).listen(8888, function() {
// send a request to the server we just created
var r = h.request({port: 8888})
r.on('response', console.log.bind(console, 'on_response'))
r.on('error', console.log.bind(console, 'on_error'))
r.on('timeout', console.log.bind(console, 'on_timeout'))
// abort will be emitted to the caller, but nothing else
r.on('abort', console.log.bind(console, 'on_abort'))
r.end()
})
You could also call socket.destroy in the connection event of the HTTP server if you're able to identify the calling agent as a bot (or whatever) somehow.
var h = require('http')
h.createServer(function(req, res) {
res.send('foo')
}).on('connection', function(socket) {
// pretend this ip address is the remote address of an attacker, for example
if (socket.remoteAddress === '10.0.0.0') {
socket.destroy()
}
}).listen(8888, function() {
// send a request to the server we just created
var r = h.request({port: 8888})
r.on('response', console.log.bind(console, 'on_response'))
r.on('error', console.log.bind(console, 'on_error'))
r.on('timeout', console.log.bind(console, 'on_timeout'))
// abort will be emitted to the caller, but nothing else
r.on('abort', console.log.bind(console, 'on_abort'))
r.end()
})
In an attempt to add a "server-side" state machine service to a single page application of Vue.js (cli), I edited following lines in webpack-dev-server/lib/Server.js:
const app = this.app = new express(); // eslint-disable-line
var globalStore ={ numRequests : 0 };
// I added this by copy-pasting another app.all('/',..) request handler.
app.all('/compute', (req, res, next) => {
globalStore.numRequests++;
res.send("num request="+globalStore.numRequests);
return next();
});
then it gave this warning each time counter is incremented:
(node:12956) UnhandledPromiseRejectionWarning: Error
[ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the
client
Still, it increments the counter, returns it successfully everytime I visit {mydomainname}/compute. Everytime it gives same warning.
I guess I'm making a simple error but can't see. Project was produced by this command:
vue init webpack vueapp01
If I delete "return next" and "res.send ('invalid host header')" lines, no warning is produced. Do I have to call "return" here always?
I am developing a rest api using express JS . I want to show several error such as route not found, data not found, validation error. I am using async await structure . I need to know how to manage several exception handling in Express JS . I search seveal website but not found exact way . Everywhere write to use nodeJS default exception . But i need it customize in REST API.
I need expert nodejs developer help . If anyone know best resource of express error handling please provide me link to learn this
1.Let for handling route not found error you can use the default route
app.all('/*', (req, res)=> res.status(404).send('Route Not Found'))
2.For handling response, you can set some predefined response in separate module and send all response from that module. Like
//response.js file
module.exports= {
ok : (res, data)=> res.status(200).send({data}),
error: (res, err)=> res.status(err.status).send({error})
}
3.For handling error you can make seperate error file where all error a set and create your error by those listed error. And you can do by try, catch
4.For validation, you can use middleware and or helper for handling validation.
5.Following are some node.js configuration link created by me, you can take reference from there
https://github.com/bapinmalakar/election-exitpoll-back (very simple, Github)
https://github.com/bapinmalakar/pt-backend (little complex, github)
You can log the error using middleware As below given example middleware we can catch the errors which are thrown across the application. Also, we can catch the promise rejections
const express = require("express");
const app = express();
app.use((err, req, res, next) => {
if (err) {
res.status(err.statusCode || 500).send(err);
console.error(err.stack);
next();
}
console.error(`Message :: ${err.message}
Url :: ${req.originalUrl}
Method :: ${req.method}
Ip :: ${req.ip}
Time :: ${(new Date()).toLocaleTimeString()}`);
});
For reference use this link. Click here
My code below gives me an error: Error: Can't set headers after they are sent.
If I put app.use('/special/... before app.use('/' ... it doesn't give me an error-
1. As I understand when using app.use the order does matter because the program doesn't look like when I use app.get for example, for anything after '/ or '/special/ so why am I getting an error?
Also when I put app.use('/special/' first I am still not seeing "first" and second" but only the first one - even though I use next..
Can someone explain?
Thanks!!
What does it mean?
var express=require ('express');
var app=express();
app.use('/',function(req,res,next){
res.send('first');
next();
});
app.use('/special/',function(req,res,next){
res.send('second');
next();
});
app.listen(3000, function(){
console.log('Server listening');
});
In your case it's nothing about order, but you can't invoke res.send('some_result') twice when one resource required,you can check this in detail Stackoverflow.
also, when you use app.use() to add middleware to your system,Express use regex to match your request url,so when you have the code below:
app.use('/',function(req,res,next){
res.send('first');
next();
});
all the request(regardless of HTTP verb) start with '/' will meet the requirement.
finally when request below:
POST /special
both of the middlewares will be invoked.
Problem
The two routes
app.use('/',function(req,res,next){
res.send('first');
next();
});
app.use('/special/',function(req,res,next){
res.send('second');
next();
});
both match the url /special. That's why both of them are executed by node. Since res.send() in the first route closes the http response from the server, the res.send() in the second router throws an error since it tries to set a header (e. g. Content-length) while output from the first route has already been sent.
Solution
Always put the more specific route first so that it is reached at all. If the first route you define matches /, no other route would ever be called.
Also, do not call next() if you want to call res.send() in routes. Best practice: next() should only be invoked in middlewares which do not send a response.
A possible solution looks like this:
var express=require ('express');
var app=express();
app.use('/special/',function(req,res){
res.send('second');
});
app.use('/',function(req,res){
res.send('first');
});
app.listen(3000, function(){
console.log('Server listening');
});
I have this simple code. This must show me my error object ({error:'error'}) upon each request. But it shows only "[Object object]".
And moreover - debugger never stops in the error handler function.
What is going on?
var domain = require('domain');
var express = require('express');
var server = express();
server.get('/', function(req, res)
{
var d = domain.create();
d.on('error', function(e)
{
debugger;
console.log(JSON.stringify(e));
});
d.run(function()
{
throw {error:'error'};
res.send('ok');
});
});
server.listen(8080);
The problem is that domains catch the error all the way at the bottom of the call stack, and since express has its own error handling code, the error gets caught by express before reaching the domain. Similar issue here: Node.js - Domain per Express request, inside another domain
I don't see any particularly good reason it should be this way, but that's how the code seems to work [1] (source here: https://github.com/joyent/node/blob/master/lib/domain.js). Possible workarounds are to surround the d.run() call with your own try/catch, or to do something like
d.run(process.nextTick(function() {
// do stuff
}));
[1] The way domains work is that they basically hook into all of the "asynchronous" callbacks and add some information that records who initiated the asynchronous operation. I don't know why they don't also try/catch on the initial synchronous block.