I am currently trying to send a 404 page that is a .pug file whenever a an ID params is not in the database. I am calling next() in the api route, and when I do it inside the elastics search callback, it will throw a page not found error as well as two Cant set header after they are sent messages. When I call the next() outside, it will properly just show the 404 error message and not the header message. I am unsure of why it is doing this.
//Doing it this way will properly send the 404 page.
app.get('/redirect/:id', function(req, res, next) {
let found = false;
if (!found) {
return next();
}
});
//But i need to check if an ID exists and then throw the 404, but doing it this way will not work and I will keep getting an error about not being able to set headers and the 404 message.
app.get('/redirect/:id', function(req, res, next) {
search.byId(req.params.id, (err, card) => {
if (err) log.log(err);
if (!card || card === undefined) {
return next();
}
});
});
In express, the next() function is for passing the control to the next middleware.
Using Express Middleware
app.use('/user/:id', function (req, res, next) {
console.log('Request URL:', req.originalUrl)
next()
}, function (req, res, next) {
console.log('Request Type:', req.method)
next()
})
In the example above, when the first next() is called the second function (req, res, next) (in express.js terms the function is called middleware) got exectued and log out the request type.
So next doesn't help you here since you are not building a middleware stack.
If you just want to render 404 page read How to redirect 404 errors to a page in ExpressJS?
Related
i'm newbie in using Authenticate a Node.js API with JSON Web Tokens, i read this document on scotch.io but i cant understand when Token is correct what happen after next() method
apiRoutes.use(function(req, res, next) {
// check header or url parameters or post parameters for token
var token = req.body.token || req.param('token') || req.headers['x-access-token'];
// decode token
if (token) {
// verifies secret and checks exp
jwt.verify(token, app.get('superSecret'), function(err, decoded) {
if (err) {
return res.json({ success: false, message: 'Failed to authenticate token.' });
} else {
// if everything is good, save to request for use in other routes
req.decoded = decoded;
next();
}
});
} else {
...
}
});
apiRoutes.get('/', function(req, res) {
...
});
apiRoutes.get('/users', function(req, res) {
...
});
apiRoutes.get('/check', function(req, res) {
...
});
app.use('/api', apiRoutes);
app.listen(port);
User must be pass other request after that (my mean is after token is correct)?
i think in this sample code / route will be call after check token and it was correct,ok? how can i choose other method to call, because / is calling after next()
actually next() asking for nodejs to go on for next step it's whatever in node.js async loop. Javascript actually single threaded so next will call whatever method placed at stack. if you will not call next() your program will stuck. and will not call any other method after this token middleware which you have passed to .use
In this particular scenario it will call the next route after verified by this token middleware, which you are passing as a anonymous function.
also have a look at this method
javascript node.js next()
I have a question on javascript syntax. Actually I came up with the coding while I was self-teaching MEAN stack tutorial (https://thinkster.io/mean-stack-tutorial#adding-authentication-via-passport). There is a very weired coding below.
})(req, res, next);
(req, res, next) seems arguments but no function utilize that arguments. Maybe I am not smart enough at this point so that I cannot see it.
Is there any guy who can help me on this? Thanks.
router.post('/login', function(req, res, next){
if(!req.body.username || !req.body.password){
return res.status(400).json({message: 'Please fill out all fields'});
}
passport.authenticate('local', function(err, user, info){
if(err){ return next(err); }
if(user){
return res.json({token: user.generateJWT()});
} else {
return res.status(401).json(info);
}
})(req, res, next);
});
To understand what's happening, you should know what "middleware" is in Express. It's a function that you can pass to Express that gets passed a request object, a response object, and a next function:
function middleware(req, res, next) {
...
}
With middleware, you can "tap" into the path that HTTP requests will follow through an Express application, and perform certain actions.
You might have already noticed that the middleware function signature looks a lot like your example code:
router.post('/login', function(req, res, next) { ... });
This is a route handler that gets called for POST requests to /login. Route handlers are similar to middleware, in that they get called with the same arguments and also perform certain actions (usually, next isn't used in route handlers, but it will still get passed as an argument).
You can "stack" middleware, too:
router.post('/login',
function (req, res, next) { ... }, // first middleware
function (req, res, next) { ... }, // second middleware
...
);
This is where next comes into play: if the first middleware isn't interested in the request, it can call next (which is a function) and the request will be passed to the second middleware (and if that middleware isn't interested in it, it can call next too, passing the request along all middleware in the app, until a middleware handles the request or it falls through, generating a 404 error, because there no middleware was found that could handle the request).
passport.authenticate() also returns a middleware function. It's usually used like this:
router.post('/login',
passport.authenticate(...),
function (req, res, next) { ... }
);
Which means that if you look at the stacking example, passport.authenticate() should return a function that accepts the three arguments req, res and next (and in fact, it does).
That means that the code above can be rewritten to this:
router.post('/login', function(req, res, next) {
passport.authenticate(...)(req, res, next);
});
Which matches the code in your question. Why you would want to call passport.authenticate() like that is a relatively advanced Passport topic.
EDIT: this is what passport.authentication, in very broad terms, looks like:
// a function that mimics what `passport.authenticate` does:
function myAuthenticate() {
return function (req, res, next) {
...some stuff...
next();
};
}
It's a function that returns a function. You can use it like this:
router.post('/login',
myAuthenticate(),
function (req, res, next) {
...
}
);
Which is (almost) the same as this:
router.post('/login',
function(req, res, next) { // <-- this is the function that got returned!
...some stuff...
next();
},
function(req, res, next) {
...
}
);
I am catching all traffic before passing it forward using:
app.all('*', function(req, res, next) {
... run before stuff, related to the next req.route.path
next();
});
and I want to run some code before calling the next() function.
in order for me to know the proper code I need to run, I have to identify what is the next request route path.
Debugging current req object (inside all('*',.. ) does not giving any information about the next request.route.path
How can I get the next method route.path before calling it?
Your help will be appreciated. Thank you.
Instead of trying to look ahead, why not explicitly set middleware for the routes that need it?
var middleware = function (req, res, next) {
..run your code in here
};
app.get('/users:user_id', middleware, function(req, res, next) {
});
You can get the next route by checking the route when the response in the middleware has fired the finish event:
app.all('*', function(req, res, next) {
res.on('finish', function() {
console.log('Next route: ', req.route.path);
});
next();
});
For a route defined like this:
app.get('/users/:user_id', function(req, res) {
res.send('Hello');
});
You'll obtain the log:
$ Next route: '/users/:user_id'
I'm trying to understand JWT and how they work with Node and Express .js. I have this middleware that tries to authenticate users with a token:
app.use(function(req, res, next) {
if(req.headers.cookie) {
var autenticazione = req.headers.cookie.toString().substring(10)
autenticazione = autenticazione.substring(0, autenticazione.length - 3)
console.log(autenticazione)
jwt.verify(autenticazione, app.get('superSegreto'), function(err) {
if (err) {
res.send('authentication failed!')
} else {
// if authentication works!
next() } })
} else {
console.log('errore')} })
And this is the code for my protected url:
app.get('/miao', function (req, res) {
res.sendFile(__dirname + '/pubblica/inserisciutente.html')
res.end() })
Even though the path is correct (I even tried with path.join(__dirname + '/pubblica/inserisciutente.html) and got the same result), when visiting the url I just get a blank page (with even node conde inside) I also set: app.use(express.static('/pubblica')) P.S. if I try to replace res.sendFile(..) with res.send('Some stuff') I can correctly view it on the page. What am I doing wrong?
res.sendFile() is asynchronous and it will end its own response if it is successful.
So, when you call res.end() right after you start res.sendFile() you are ending the response before the code has actually sent the file.
You can do it like this:
app.get('/miao', function (req, res) {
res.sendFile(__dirname + '/pubblica/inserisciutente.html', function(err) {
if (err) {
res.status(err.status).end();
}
});
});
See the Express doc for res.sendFile() here.
if you want to end the response with res.end() then you must not mention or specify it after res.sendFile() because res.sendFile() is an asynchronous function that means it will take some time to execute and in that meantime next instruction which is in your case is res.end() will execute and that's why you didn't see any response send by the res.sendFile
You can visit the documentation to know more about res.sendFile() visit documentation
I would like to achieve something like this:
var c = require('connect');
var app = c();
app.use("/api", function(req, res, next){
console.log("request filter 1");
next();
});
app.use("/api", function(req, res, next){
console.log("request filter 2");
next();
});
app.use("/api", function(req, res, next){
console.log("request handler");
res.end("hello");
next();
});
app.use("/api", function(req, res, next){
console.log("response post processor");
next();
});
app.listen(3000);
When I curl for the address, I get an exception to the console complaining about headers cannot be bothered after being sent which is fair enough. Only that I do not touch the response object.
/usr/bin/node app2.js
request filter 1
request filter 2
request handler
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (http.js:644:11)
at ServerResponse.res.setHeader (/home/zpace/node_modules/connect/lib/patch.js:59:22)
at next (/home/zpace/node_modules/connect/lib/proto.js:153:13)
at Object.handle (/home/zpace/WebstormProjects/untitled1/app2.js:25:5)
at next (/home/zpace/node_modules/connect/lib/proto.js:190:15)
at Object.handle (/home/zpace/WebstormProjects/untitled1/app2.js:19:5)
at next (/home/zpace/node_modules/connect/lib/proto.js:190:15)
at Object.handle (/home/zpace/WebstormProjects/untitled1/app2.js:14:5)
at next (/home/zpace/node_modules/connect/lib/proto.js:190:15)
at Function.app.handle (/home/zpace/node_modules/connect/lib/proto.js:198:3)
Debugging the NodeJS/Connect layer I got into a part that somehow implies that if headers are already sent then executing a route handler must initialize response headers.
The question is if the above mentioned behavior is intentional (ie that the execution of any code after a route handler has finished sending a response is something utterly unimaginable or this is simply a bug in connect?
Not sure whether you have found your solution.
If you want to design a post-processor for the request cycle, you can use a middleware that listens to the "finish" event on the response object. Like this:
app.use(function(req, res, next){
res.on('finish', function(){
console.log("Finished " + res.headersSent); // for example
console.log("Finished " + res.statusCode); // for example
// Do whatever you want
});
next();
});
The function attached to the "finish" event will be executed after the response is written out (which means the NodeJS has handed off the response header and body to the OS for network transmission).
I guess this must be what you want.
I think this is a bad planning problem. You should solve this in a better way. I dont know why you have a request handler and a request post processor separated, but lets find out what we can do.
So yes, after response has ended you cant read the headers again.
So dont finish the response until the post processor is invoked.
var isEnd;
app.use("/*", function(req, res, next){
isEnd = false;
})
app.use("/api", function(req, res, next){
console.log("request handler");
res.write("hello");
isEnd = true;
next();
});
app.use("/api", function(req, res, next){
console.log("response post processor");
if(isEnd) {
res.end();
}
else next();
});
This is a kind of solution, but this may not be the best for your problem.
In my opinion it is really bad that you call next() after the response has been finished. If you need a post processor, why you do that in a request filterer (or what is this). Call a function but not next()
Maybe this:
app.use("/api", function(req, res, next){
console.log("request handler");
res.end("hello");
setTimeout(function(){(postProcessor(req)},0);
});
function postProcessor(req) {
//doing post process stuff.
//response not needed because already ended.
}
Or this:
app.use("/api", function(req, res, next){
console.log("request handler");
res.writed("hello");
setTimeout(function(){(postProcessor(req)},0);
// u cant res.end here because setTimeout.
//If you dont use setTimeout you can use res.end here, but not bot function.
});
function postProcessor(req, res) {
//doing post process stuff.
res.end();
}
The next() is not for that usage, what you uses.
I hope my answer helps you, but i know it not covers everything, but your answer is not really concrete too.
What a great question to try work out with your morning coffee!
So looking through proto.js, if you have a look down to line 102 which is app.handle which is the handler code for the middleware stack, you'll see how next() operates.
Where the function next() is called, you can see it checks if res.headerSent is true and if so it throws an error.
If modify line 14 to:
app.use("/api", function(req, res, next){
console.log("request handler");
res.end("hello");
console.log(res);
next();
});
You will see that it actually sets "headersSent" to true. So after we've ended the request, you can see from the next() code that it throws the error because of the conditions discussed.