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...
Related
setting
app.use("/api/tobaccos", tobaccos);
app.use(function(err, req, res, next) {
console.error(err.message);
});
api:
router.get("/:id", async (req, res) => {
console.log("GET TOBACCO:" + req.params.id);
await Tobacco.findById(req.params.id)
.then(tobacco => res.status(200).json({ status: "success", data: tobacco }))
.catch(error => res.status(404).json({
status: "fail",
msg: "Tobacco not found!",
code: "error.tobaccoNotFound"
}));
});
I'm trying to add middleware for all 404 errors
app.use(function(err, req, res, next) {
console.error(err.message);
});
or this doesn't work
app.get('*', function(req, res){
res.status(404).send('what???');
});
What is wrong?
In Express, 404 responses are not the result of an error, so the error-handler middleware will not capture them. This behavior is because a 404 response simply indicates the absence of additional work to do; in other words, Express has executed all middleware functions and routes, and found that none of them responded. All you need to do is add a middleware function at the very bottom of the stack (below all other functions) to handle a 404 response:
app.use(function (req, res, next) {
res.status(404).send("Sorry can't find that!")
})
Add routes dynamically at runtime on an instance of express.Router() so the routes are not superseded by a middleware function.
Reference: https://expressjs.com/en/starter/faq.html
You can add this middleware in your root file. It sends error for any invalid routes.
//Handles 404 errors
app.use((req, res, next) => {
const error = new Error('Error Occured');
error.status = 404;
next(error);
});
app.use((error, req, res, next) => {
res.status(error.status || 500);
res.json({
error: {
message: error.message
}
});
});
Alternatively, you can try which captures all 404 errors
app.use(function(req, res, next) {
res.status(404).send( 'Error Occured! ');
});
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();
}
}
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.