I was wondering how should I be dealing with response and next in express.
My understanding is that when I say res.send(...) -> returns a response
If I want to throw an error, I say next(new Error('whatever')) -> auto sets the http status code using express errorhandler.
I am able to do either of those but not but, looks like I am messing up.
Can anyone give an example?
I tried,
somefunc(err, req, res, next) {
if(err) {
res.send(500, 'some error');
return next(err);
}
}
return [somefunc, express.errorHandler()];
thanks.
You can register some middleware to handle errors:
app.use(function(err, req, res, next){
console.error(err.stack);
res.send(500, 'Something broke!');
});
You can also simply send a 500 with your response if you encounter an error in your logic
function loginUser(req, res, next) {
try {
var valid;
//code to check user
if (valid) {
next();
} else {
res.send(401, 'not authorized');
}
} catch (err) {
res.send(500, 'Oopsy');
}
}
app.get('/some/route',loginUser, function(req, res) {
// ...
});
Just skip return next(); part. Use return res.send(500,'some error'); Calling next causes next middleware to be called which IMO is not what you want in this case. I wrote more about it here.
Here is minimal example of express stack:
express = require('express');
app = express();
app.configure(function() {
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(app.router());
app.use(express.static(__dirname + '/public'));
});
app.get('/', function(req, res) {
if (some error)
res.send(500, 'Some error');
else
res.send('<body>Hello</body>');
});
app.listen(3000); // listen on port 3000
The get request will be called by router middleware. Middlewares are parsed as chain. You can use custom middleware in this chain, for example:
app.configure(function() {
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(function(req, res, next){
if (some condition)
res.send(500, 'No way'); // this will break the request chain
else
next(); // this will continue processing and will call app.router middleware
});
app.use(app.router());
app.use(express.static(__dirname + '/public'));
});
app.router middleware is responsible for calling appropriate method based on requested URL (like app.get('/')). If it fails to find one, it calls next() to pass control to express.static middleware which tries to find static file in /public/ folder.
Related
1.Can anyone tell me how to allow my error to pass through the app.use('/blogs','blogRoutes') middle ware that scopes my url to a api file?
2.Is the answer something like app.use('/blogs','blogRoutes', next){next(err)}?
const express = require('express');
const morgan = require('morgan');
//use Mongo Db
const mongoose = require('mongoose');
const blogRoutes = require ('./route/blogroutes');
const app = express();
//connect to mongo db
const dBurI = mongo database key
mongoose.connect(dBurI, {useNewUrlParser: true, useUnifiedTopology: true});
.then((result)=> app.listen(3000))
.catch((err)=>console.log(err))
//middleware stack
// allows use of view engine to render - html files in views foles are suffixed with ejs these are found automatically due to views folder beign recognised
app.set('view engine','ejs');
app.use(express.static('public')); //access ppblic folder files - css
app.use(express.urlencoded({extended: true})); //url data and passes into object that can be used on req => req.body
app.use(morgan('dev'));
//redirect route
app.get('/',(req, res, next)=>{
res.redirect('/blogs');
next(err);
});
app.get('/about',(req, res, next)=>{
//send file to a browser
res.render('about', {title: 'About' });
next(err);
});
//redirect 301
app.get('about-me',(req,res, next)=>{
res.redirect('./about');
next(err);
});
//blogroutes
app.use('/blogs','blogRoutes'); //scope all blog urls to blogrouter
// middle ware app.use is called immediately if above are not found - error page 404
app.use((err,req,res)=>{
res.status(404).render('404', {title: '404', error: err });
});
1.after reading the express documentation I believe the answer for espress5+ is as follows:
//redirect route
app.get('/',(req, res, next)=>{
res.redirect('/blogs');
});
app.get('/about',(req, res, next)=>{
//send file to a browser
res.render('about', {title: 'About' });
});
//redirect 301
app.get('about-me',(req,res, next)=>{
res.redirect('./about');
;
});
//blogroutes
app.use('/blogs','blogRoutes',(req,res,next)); //scope all blog urls to blogrouter
// middle ware app.use is called immediately if above are not found - error page 404
app.use((err,req,res, next)=>{
res.status(404).render('404', {title: '404', error: err });
});
2.read this doucmentations and see if im write if not then I believe I have to do this:
//redirect route
app.get('/',(req, res, next)=>{
res.redirect('/blogs');
next(err);
});
app.get('/about',(req, res, next)=>{
//send file to a browser
res.render('about', {title: 'About' });
next(err);
});
//redirect 301
app.get('about-me',(req,res, next)=>{
res.redirect('./about');
next(err);
});
//blogroutes
app.use('/blogs','blogRoutes',(req,res,next)=>{next(err);}); //scope all blog urls to blogrouter
// middle ware app.use is called immediately if above are not found - error page 404
app.use((err,req,res, next)=>{
res.status(404).render('404', {title: '404', error: err });//next would call the express error handler automatically if used here..
});
Following is the error handling behaviour in Express - 4.17:
You do not need to explicitly pass the error to the error handling middleware for synchronized operation. Express will take care of it for you. This can be confirmed by sending a GET request to the / route. In this case, your app does not crash.
If an error occurs during async operations, you must explicitly pass the error to the next middleware using next(). I created two routes to test this behaviour: /async and /async_next. If you visit the /async route, your app should crash because we are not explicitly handling the error. Once you restart your app and navigate to the /async_next route, you will notice that it does not crash and that the error is handled by the custom error handling middleware.
For understanding the above points refer to the following code -
const express = require('express');
const app = express();
app.listen('3001', () => console.log("listening port - 3001"));
app.get('/async', (req, res, next) => {
console.log('Async function');
setTimeout(() => { throw new Error('Async Err from settimeout') }, 1);
})
app.get('/async_next', (req, res, next) => {
console.log('Async function');
setTimeout(() => {
next(new Error('Async Err from settimeout'))
}, 1);
})
app.get('/', (req, res, next) => {
throw new Error('Random Sync Err');
});
app.use((err, req, res, next) => {
console.log('Error from custom handler ', err);
res.send('Error');
});
1.so this seems right but need testing...
//redirect route
app.get('/',(req, res, next)=>{
res.redirect('/blogs');
});
app.get('/about',(req, res, next)=>{
//send file to a browser
res.render('about', {title: 'About' });
});
//redirect 301
app.get('about-me',(req,res,next)=>{
res.redirect('./about');
});
//blogroutes
app.use('/blogs','blogRoutes',(req,res,next)); //scope all blog urls to blogrouter
// middle ware app.use is called immediately if above are not found - error page 404
app.use((err,req,res,next)=>{
res.status(err.status).render('404', {title: 'Error Page', error_message: 'err.message'});
}):
You error handler needs to look like this even with express 5+
function errorHandler (err, req, res, next) {
if (res.headersSent) {
return next(err)
}
res.status(500)
res.render('error', { error: err })
}
You need the err argument to reference to the error...
I'm trying to run a middleware inside another middleware. When I call the nested middleware, I get an error saying:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
Here's my code:
// middleware1
module.exports = function(req, res, next) {
req.user = 'current user';
next();
};
// middleware2
module.exports = function(req, res, next) {
middleware1(req, res, next);
if (req.user !== 'current user') return res.status(403).send('Access denied');
next();
};
// API
router.get('/api', middleware2, async (req, res) => {
return res.send(req.user);
});
What am I doing wrong, and what's the correct way to chain or nest a middleware into another one?
(The web app has more to it, but I only included whatever is necessary to reproduce the error)
Following on #jknotek comments:
Since you are passing the next function from middleware2 to middleware1, you are risking that the final middleware gets called in the part of the call stack, which triggers res.send. Afterwards it proceeds in middleware2, which tries to do a res.status, which will fail.
Either you want to chain middlewares as:
router.get('/api', middleware1, middleware2, [...])
Or you would want your middleware2 to behave somewhat like:
//middleware2
module.exports = function(req, res, next) {
middleware1(req, res, () =>
if (req.user !== 'current user') return res.status(403).send('Access denied');
next();
);
};
when dealing with routes, I want to check if the route is valid. If not, I always want to redirect to a notFound page.
If the user is not authorized I always want to redirect to the login page.
Otherwise I want to use the valid routes.
In my app.js I require my router.js and pass in the app as a parameter
require('./server/router')(app);
So my router works fine when having
module.exports = function(app){
app.use('/route1', require('./routes/route1'));
app.use('/route2', require('./routes/route2'));
app.use('/route3', require('./routes/route3'));
};
in there. When using this structure
module.exports = function(){
var router = require('express').Router();
router.use('/route1', require('./routes/route1'));
};
it results in
Cannot GET /route1
All my routes contain this base structure
var router = require('express').Router();
// -- Route --
router.get('/', function (req, res) { // Render the HTML here
res.render('route1', {
});
});
// -- Ajax POST --
router.post('/doSomething', function (req, res) { // Load some data
res.send({});
});
module.exports = router;
Is it not possible to use the router when it comes to require the routes?
Further I want to implement the check for invalid routes or authorized users.
app.use(function(req, res, next) {
if(!req.route){
res.redirect('/notFound'); // invalid route
} else {
var session = req.session;
if (session.user == null){ // unauthorized user
res.redirect('/login');
} else {
// valid routes here
}
}
});
How can I connect this pseudo code with my valid routes?
put at the end of your express app.js
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
if(err.status == 404) res.redirect('/notFound')
// can handle more conditions (like 500) also
})
You have to create a middleware for checking authorized users on top of all routes, and another to handle not found routes at the end:
handle unauthorized users:
app.use(function(req, res, next) {
if (!req.session.user) {
return res.redirect('/login');
}
next();
});
catch not found routes:
app.use(function(req, res, next) {
res.status(404).send('Page Not Found');
});
You may want to render error view by using res.render('error', {code: 404, msg: 'Page Not Found'});
I am trying to implement a middleware that will check if a user is authenticated before the server delivers a page. Although it looks like the process of doing this is simple, node is throwing an error which says "Can't set headers after they are sent".
My router's code is:
module.exports = function(app) {
app.get('/', checkAuth, require('./myAuthenticatedPage').get);
app.get('/login', require('./myLoginPage').get);
};
The myAuthenticatedPage.js:
exports.get = function(req, res) {
res.render('index');
};
The myLoginPage.js:
exports.get = function(req, res) {
res.render('login');
};
The checkAuth.js:
module.exports = function (req, res, next) {
if(!req.session.user) {
res.redirect('/login');
}
next();
}
Any help on this will be greatly appreciated.
Thanks
If you aren't authenticated, you'll redirect the user and then try to render the index page. This causes the http headers to be sent twice, hence the error "Can't set headers after they are sent".
In checkAuth.js try:
module.exports = function (req, res, next) {
if(!req.session.user) {
res.redirect('/login');
} else {
next();
}
}
using express.js for a project, first time using it for much more than messing around, and having some trouble with getting middleware to play nice.
My problem is that calls to my express static route, declared close to the top of the file
app.use(express.static(__dirname + '/public'));
are actually being handled by the error handler, almost at the bottom of the file
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
...and I'm unsure why. I know that JS isn't necessarily executing stuff in order, but it was my understanding that express will execute these in order, and app.use stuff at the bottom will occur after app.use stuff at the top - hence the need for next(); - to pass to the next app.use handler?
Any ideas/wisdom? Any help appreciated.
I have this code:
// Initial variable setup
var
express = require('express'),
favicon = require('serve-favicon'),
logger = require('morgan'),
cookieParser = require('cookie-parser'),
bodyParser = require('body-parser'),
swig = require('swig'),
stylus = require('stylus'),
nib = require('nib'),
fs = require('fs'),
app = express()
;
app.use(express.static(__dirname + '/public'));
app.engine('html', swig.renderFile);
app.set('view engine', 'html');
(settings.deploymentMode === 'dev') && app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
function compile(str, path) {
console.log('STYLUS: Compiling CSS');
return stylus(str)
.set('filename', path)
.set('compress', true)
.use(nib())
.import('nib');
}
app.use(stylus.middleware(
{
src: __dirname + '/public',
compile: compile
}
));
// Got some routing going on here... app.get statements, all working fine.
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('system/error', {
message: err.message,
error: err
});
});
} else {
// Production error handler - #TODO: Rewrite this one first.
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('system/error', {
message: err.message,
error: {}
});
});
}
module.exports = app;
Express error handling middleware is defined using four params, not three.
// From the specs
app.use(function(err, req, res, next){
console.error(err.stack);
res.status(500).send('Something broke!');
});
If you only defined it with 3 params, then it considers it a "normal" middleware and will call it unless a previous middleware, ends the request instead of calling next(). It appears that static middleware calls next(), probably to allow later middleware to log or compress its data.