Here's my code
mysql = require('mysql');
con = mysql.createConnection(connectionSetttings);
app.get('/users/list', ensureLogin, function (req, res, next) {
con.query(query.getUserList, [req.user.innId], function (err, rows) {
if (err) {
next(err); // also tried: return next(err)
} else {
displayUsers();
}
});
}, function (err) {
console.error(err);
displayErrorPage(500);
});
I run it with the MySQL server not running to see if Express would render the error page or not. The problem is, Express simply barfs up the stack into the browser. Is there anything wrong with my code? How do I properly chain middlewares?
Define error-handling middleware functions in the same way as other middleware functions, except error-handling functions have four arguments instead of three: (err, req, res, next).
Make sure to add the error handling to the app afterthe routes.
var app = require('express')();
app.get('/users/list', ensureLogin, function (req, res, next) {
con.query(query.getUserList, [req.user.innId], function (err, rows) {
if (err) {
next(err);
} else {
displayUsers();
}
});
});
// Error handling middleware
app.use(function (err, req, res, next) {
displayErrorPage(500);
});
When using MySQL as a session store, session-related middlewares attached using app.use() will intercept requests for all routes and malfunctions. This will make seemingly unrelated routes throw HTTP500 even if it doesn't look like they invoke return next(err).
The solution to this is to only attach any session-related middleware to necessary routes. Alternatively, you can wrap them in a filter function like this one:
var middlewareFilter = function(middleware) {
// Return whatever function that is returned by this function
// to be used in app.use()
return function (req, res, next) {
// Set the routes to be ignored.
var exceptionList = [
'images',
'stylesheets',
'scripts'
];
// Cast req.url to string so it can use JS's string methods
var path = String(req.url);
// If path matches any of the exceptionList...
if (array.contains(path.split('/')[1], exceptionList)) {
// ...just do nothing
return next();
} else {
// Otherwise, return the middleware
return middleware(req, res, next);
}
}
}
And use them like app.use(session(sessionConfig));
Related
How to implement middleware like this in socket.io? Please help
EXPRESS APP
var myLogger = function (req, res, next) {
console.log('LOGGED')
next()
}
app.use(myLogger)
app.get('/', function (req, res) {
res.send('Hello World!')
})
SOCKET APP (I am using express pattern but its not working)
var myLogger = function (data,next) {
console.log('DOING DATA VALIDATION...')
next()
}
io.use(myLogger)
io.on('someEvent/', function (data, callback) {
callback('Hello World!')
})
Error : next() is not define!
app.use(function (req, res, next) {
req.io = io;
next();
});
This assigns a socket object to every request.
If somebody's still wondering.
To use middleware on all sockets:
io.use((socket, next) => {
// isValid is just a dummy function
if (isValid(socket.request)) {
next();
} else {
next(new Error("invalid"));
}
});
This example is from the official docs of socket.io
To use a middleware for a specific client:
io.on('connection', async (client) => {
client.use((socket, next) => {
console.log(`got event: ${socket[0]} in client middleware, moving on with next() just like in express`)
next()
});
// rest of your code
newConnection(client)
})
Environment: node.js, Express
I'm attempting to use an error handling pattern based on work done by Valeri Karpov (creator of Mongoose). He explains the pattern that he uses in this article, The 80/20 Guide to Express Error Handling.
In the simplified server below I can successfully feed errors through to my error handling middleware.
const express = require('express');
const app = express();
app.set('view engine', 'ejs');
app.get('/', async function(req, res, next) {
let catStatus = false;
function answer(X) {
return new Promise( function(resolve, reject) {
if(X) {
resolve('cat does exist');
} else {
reject('whoops, cat does not exist');
}
});
}
answer(catStatus)
.then( function(data) {
res.render('index', { output: data });
})
.catch( function(error) {
next(new Error(error));
});
});
app.use( function(error, req, res, next) {
res.render('error', { error });
});
app.listen(8080, function(){
console.log('listening on port 8080');
});
However I'm stuck on how to implement his wrapper pattern with my basic setup. Does the code inside my '/' endpoint go inside of his '*' endpoint?
If so does anything go inside of his function wrapAsync(fn)? Should I just delete his 2 comment lines and leave it as is?
app.get('*', wrapAsync(async function(req, res) {
await new Promise(resolve => setTimeout(() => resolve(), 50));
// Async error!
throw new Error('woops');
}));
app.use(function(error, req, res, next) {
// Gets called because of `wrapAsync()`
res.json({ message: error.message });
});
app.listen(3000);
function wrapAsync(fn) {
return function(req, res, next) {
// Make sure to `.catch()` any errors and pass them along to the `next()`
// middleware in the chain, in this case the error handler.
fn(req, res, next).catch(next);
};
}
I think the * endpoint in app.use() is just a wildcard saying to route all incoming requests to that code, similar to the way your / is working.
But yes, you are understanding correctly. Basically, he is saying that any middleware which makes asynchronous requests should use this wrapAsync function. You can remove the comment lines in the wrapAsync implementation if you want.
With the wrapAsync function, you can pass your own async middleware functionality into this wrapper, and it will make sure to call your async middleware and .catch() the promise to call next, so that you don't have to worry about that detail when writing code. You can simply throw errors, and then async wrapper will handle the Express requirement of calling next() when async code fails.
app.use("/", (req, res, next) => {
verifyRequestorPermissionsAsync(req.params)
.catch(err => {
return next(err);
});
});
With the wrapAsync middleware, you will automatically call next with the rejected error (if there is one), so you can clean up the code quite a bit (as well as avoid accidentally forgetting to call next on a rejection).
app.use("/", wrapAsync(async(req, res, next) => {
await verifyRequestorPermissionsAsync(req.params);
}));
These two docs / articles will help clear things up a lot, if I am guessing correctly where the confusion is coming from:
Why do we even care about next and passing a value into that function: https://expressjs.com/en/guide/error-handling.html
What is this wrap function doing, which returns a function that calls your function? https://eloquentjavascript.net/03_functions.html#h_hOd+yVxaku
I tried to use middleware errorhandler, but doesn't work, even i set process.env.NODE_ENV ='development'
below is the server code:
var express = require('express');
var app = express();
var errorhandler = require('errorhandler');
var notifier = require('node-notifier');
process.env.NODE_ENV = 'development'; //just purposely do this, see if it can work
if (process.env.NODE_ENV == 'developmet') {
app.use(errorhandler({ log: errorNotification }));
}
function errorNotification(err, str, req) {
var title = 'Error in' + req.method + '' + req.url;
notifier.notify({
title: title,
message: str
});
}
app.get('/', function (req, res, next) {
nonexist(); //the error is still captured Native node.js not errorhandler
res.send('this is home page!');
next();
});
app.listen(1338);
no matter what kind of options i tried in errorhandler, it still doesn't work.
can anyone help me to check any setting is wrong?
Error handling is declared after all your other routes. Express moves through routes from top to bottom or left to right (if you imagine all your code on one line).
You can capitalize on this by putting a splat route after all your other routes, and it will be activated if no other exact route matches. This is how you can do an error 404 page.
It's why you build your routes like this (which will prepare you for React Router 'switch component', if you move into React coding):
GET /test/:slug
GET /test
GET /
Here is an example of a splat route and following that, your error handler middleware:
// Try switching the order of these first two
app.get('/', async (req, res, next) => {
return res.status(200).send('test')
})
app.get('*', async (req, res, next) => {
return res.status(404).send('error 404') // res.render('error/404')
})
// ERRORS
app.use(async (err, req, res, next) => {
// if next() is called with a parameter, which can be anything,
// this middleware will fire
res.status(500).send('error 500') // res.render('error/500')
throw err
})
// Try replacing your default route with this now
app.get('/', async (req, res, next) => {
return next('Extreme detonations')
})
You do not need the async functions as I have shown here, but I do it as a matter of convention so I can always slap await in there. I use explicit returns to prevent any issues with sending headers after they are already sent, and because async functions return promises, so explicit return will resolve them.
All my routes generally look like this:
app.get('/admin', async (req, res, next) => {
try {
if (!req.user) throw 'garbageUser'
const poop = await something()
return res.render('template', {
data: obj,
bonusData
})
} catch (e) {
if (e === 'garbageUser') {
log.add(`illegal: ${req.originalUrl} from ${sniffer.getClientIp(req)}`)
return res.render('403')
}
return next(e)
}
})
This should hopefully be informative for you and offer some code to forensically analyze. The Express error handler middleware takes a 4th parameter in the first position called err which contains the value passed into next().
Check out the Express documentation again after studying this, and it will make much more sense :)
To answer your question:
var express = require('express');
var app = express();
// You can add these back now that you understand
// var errorhandler = require('errorhandler');
// var notifier = require('node-notifier');
function handleErrors(error) {
console.log('I'm telling your mom about this: ' + error);
}
app.get('/', function(req, res, next) {
return next('REALLY BAD');
return res.send('this is home page!');
});
// Remember, this must be after all your other routes
app.use(function(err, req, res, next) {
console.log('Problem occurred, we could put logic here...');
console.log('Error was: ' + err);
if (err === 'REALLY BAD') {
handleErrors(err);
}
next();
});
app.listen(1338);
Try commenting this out now return next('REALLY BAD'); and run it again. You should see "this is home page!".
When you call next() with no parameter in it, Express treats it as no error. If you pass any value in, like next(err) or next('Chicken tastes good'), you will see err defined with that value in your error handling middleware.
I implemented a very simple middleware to check the permissions for the user:
app.js
...
var security = require('./lib/security');
app.use(security.init);
...
lib/security.js
var session;
var request;
var response;
function init(req, res, next) {
request = req;
response = res;
session = req.session;
next();
}
function adminRequired(){
if (!isAdmin()){
response.redirect('/login');
response.end();
return true;
}
return false;
}
...
The best way I found to interrupt the flow is the following:
routes/mycontroller.js
router.get('/', function(req, res, next) {
if(security.adminRequiredHtml()){return;} // now it actually interrupt the execution
res.render('admin',{});
res.end();
});
However, I would like to use it like this:
routes/mycontroller.js
router.get('/', function(req, res, next) {
security.adminRequiredHtml(); // <- interrupt the request
res.render('admin',{});
res.end();
});
It correctly perform the redirect, but the execution continues :(
I've tried a few solutions like but it doesn't really work:
response.end() -> close the output but continues the execution
process.end() -> it's too radical, terminates the execution but it also kill the server :(
I've been thinking about using a throw but I don't know where to catch it and make it terminate gracefully (no stacktrace)
You could create a custom Router that is secured and add your secure Routes to that:
var secureRouter = express.Router();
// every request on this router goes throug this
secureRouter.use('*', function (req, res, next) {
if(isAdmin()) next();
// if you don't call next() you interrupt the request automaticly
res.end();
});
// protected routes
secureRouter.get('/user', function(req, res){/* whatever */});
secureRouter.post('/user', function(req, res){/* whatever */});
app.use(secureRouter);
// not protected
app.get('/api', function(req, res){/* whatever */});
Express doc for using middlewares
You're actually looking for middleware, I think.
function myMiddleware (req, req, next) {
if (!isAdmin()) {
res.redirect('/login');
res.end();
} else {
//Proceed!
next()
}
}
router.get('/', myMiddleware, function(req, res, next) {
res.render('admin',{});
res.end();
});
You can chain as many of those as you'd like to handle whatever logic you need. Just make sure you call next() if you're supposed to move on!
I wrote a middleware for Connect and Express that requires some heavy lifting in its setup method. Due to the nature of the initialization tasks this stuff is asynchronous, so I have the problem that the middleware shall only be accessible once the initialization has been run.
Currently I have solved it using a callback:
function setupMiddleware(callback) {
doSomeAsyncInitialization(function () {
callback(function (req, res, next) {
// The actual middleware goes here ...
});
});
}
This works, but it's not nice for the caller. Instead of being able to do
app.use(setupMiddleware());
I have to do:
setupMiddleware(functin (middleware) {
app.use(middleware);
});
Now I was thinking whether there is a better approach, e.g. let the middleware initialize in the background and delay all incoming requests until the middleware is ready.
How could I solve this? Any ideas or best practices that I should use here?
I now solved it using an isInitialized variable and delaying the middleware function itself. See the following example:
var connect = require('connect');
var setup = function () {
var isInitialized = false;
setTimeout(function () {
isInitialized = true;
}, 10000);
function run (req, res, next) {
res.write('Foo');
res.end();
}
function delay (req, res, next) {
if (isInitialized) {
return run(req, res, next);
}
setTimeout(function () {
delay(req, res, next);
}, 1000);
}
return function (req, res, next) {
if (req.url === '/foo') {
delay(req, res, next);
return;
}
next();
}
};
var app = connect();
app.use(setup());
app.use(function (req, res) {
res.write('Fertig!');
res.end();
});
var http = require('http');
http.createServer(app).listen(5000);
Please note that this code has not been optimized or refactored in any way, it just is a demonstration that the idea itself works.
Why you don't do like as follows,
doSomeAsyncInitialization(function () {
//After doing all long running init process just configure your express as follows.
app.use(<middlewares>);
app.listen(<portnumder>);
});