ExpressJs res.sendFile doesn't work after middleware - javascript

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

Related

next() and sending 404 page

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?

next() isn't skipping over the rest of the middleware

I'm very much a newbie to the whole express routing logic (and node and js for that matter). But I have problem that I can't seem to trace, but I think I understand the context of it. Well now, that didn't make a lot of sense, here it goes anyway.
I'm trying to skip through middleware conditionally based on data in the req.query and it renders the intended form page fine except for the fact that I get 'Cannot send header twice ...' in the console from the previous middleware, which i thought i skipped.
From what I can gather next() should get me to the next middleware instantly and skip the rest of the block entirely (kind of like how a return kicks you out of a function). Is this not correct?
path: localhost:3000/JohnnyBoy?action=form
router.get('/:name/', function(req, res, next) {
if(req.query.action !== 'view') { next(); };
console.log('Why am I seeing this in the console?');
res.render('first', {
title: req.params.name
});
});
router.get('/:name/', function(req, res, next) {
res.render('form', {
title: req.params.name + ' This is a form page',
formFields: fields.userPostFields()
});
});
You need to put return; after calling next(); only calling next() will not stop execution of the current function.
Replace
if(req.query.action !== 'view') { next(); };
with
if(req.query.action !== 'view') { next(); return;};

URL rewriting not working in Express 4.14.1

I've found in quite a few SO posts that in order to rewrite a URL in Express 4 I would do something like the following:
router.use('/one/:someId', (req, res, next) => {
req.url = `/two/${req.params.someId}`;
next();
});
router.get('/one/:someId', (req, res) => {
res.send("reached /one/:someId");
});
router.get('/two/:someId', (req, res) => {
res.send("reached /two/:someId");
});
But when I try this, not only does the URL does not change to my expected "/two/some integer" and stays being "/one/some integer" but it gets to the 404 - Not Found page I have set up in my app file.
This routes are in a router file and I have also tried setting the URL to:
req.url = `/routerPath/two/${req.params.someId}`;
but the result is exactly the same.
So what could I be missing?
Thank you.
You have to distinguish two kinds of redirects:
Internal redirects work on the server, without the client noticing. They are a convenience for your server programming and never necessary - you could always introduce a helper method that gets called by all endpoints.
HTTP redirects advise the client (e.g. a web browser) to go to a different URL. Since you expect the URL to change, that's the one you want.
Simply call res.redirect, making sure to encode special characters:
router.get('/one/:someId', (req, res) => {
res.redirect(`/two/${encodeURIComponent(req.params.someId)}`);
});
router.get('/two/:someId', (req, res) => {
res.render("reached /two/:someId");
});

NodeJs what happen when Token is correct on next() method?

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()

How to have a NodeJS/connect middleware execute after responde.end() has been invoked?

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.

Categories

Resources