I'm newish to NodeJS and ExpressJS and am trying to get the session management flow in main.js worked out.
What I currently have that's working:
app.get('*', function(req, res){
var page = getPage();
session_.initSession( req, res, function( ){
loggedIn = false;
if( req.session && typeof req.session.username !== "undefined" ){
loggedIn = true;
userFName = req.session.first_name;
userLName = req.session.last_name;
}
if( !loggedIn ){
res.render('pages/login', { message: "<div class='notice centered' style='width: 40%;'>Please login</div>" });
returnFlag = true;
return;
} else {
if (page.length < 1){
// render index page here ...
returnFlag = true;
return;
}
// render 'test' page
if( page == 'test' ){
// do test functions here...
returnFlag = true;
return;
}
}
});
if( returnFlag == true ){
return;
}
res.render('partials/home', { message: "404 not found (unknown page GET request)" });
return;
});
app.post('*', files, function(req, res){
var page = getPage();
if( page == 'test' ){
// do test functions here...
returnFlag = true;
return;
}
if( returnFlag == true ){
return;
}
res.render('partials/home', { message: "404 not found (unknown page POST request)" });
return;
});
The problem with this is that POST requests are being processed even when no session is in place. I've tried adding app.all/use blocks above the app.get and app.post code blocks to set up a session, but then the app.get/post blocks were not getting processed. What is the optimal way to architect this so all requests get filtered through session management and then on to page request blocks if a proper session is in place?
A Middleware function in Express is what you're looking for.
Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. The next middleware function is commonly denoted by a variable named next.
Learn more from Express's Documentation - here
A Middleware can be connected like a chain and is processed in the sequence you write it in. As long as you're executing the 'Next' function, you can link as many as you would like.
So before the POST requests are actually processed, you can exit out and redirect the user, otherwise execute the next function to continue processing.
Here is an example of how you could simplify your code.
function _sessionAuthorization(req, res, next) {
if(typeof req.session.username == "undefined") {
return res.redirect("/login");
} else {
next();
}
}
app.get('*', function(req, res){
res.render('partials/home', { message: "404 not found (unknown page GET request)" });
});
app.post('*', files, _sessionAuthorization, function(req, res){
res.render('partials/home', { message: "404 not found (unknown page POST request)" });
});
Related
I am using Facebook Graph NodeJS API to fetch user_posts. The response has pagination and therefore I need to loop over the response to fetch all the posts. I am using following route to fetch facebook posts and I am looping over pagination using get_user_statuses function:
var posts = "";
function get_user_statuses(response_posts, res) {
var link_regex = /https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,}/g;
var isNextPageAvailable = true;
if ("paging" in response_posts) {
var nextPage = response_posts.paging.next;
isNextPageAvailable = true;
} else {
isNextPageAvailable = false;
}
for (var i = 0; i < response_posts.data.length; i++) {
var post = response_posts.data[i].message + " ";
if ("message" in response_posts.data[i]) {
posts += post.replace(link_regex, "");
}
}
if (nextPage !== undefined) {
request(nextPage, function (error, response, body) {
if (!error && response.statusCode === 200) {
get_user_statuses(JSON.parse(body));
} else {
console.log(error);
}
});
}
if (!isNextPageAvailable){
//Sending posts to facebook Modal
console.log(posts);
res.send(JSON.stringify({posts: posts})); //res is not defined here
}
}
router.post('/fbData', function (req, response, next) {
FB.setAccessToken(req.body.access_token);
FB.api('/me?fields=posts&posts.limit=1000', function (res) {
if (!res || res.error) {
if (!res) {
response.send(JSON.stringify({error: 'An error occurred. Please try again.'}))
}
response.send(JSON.stringify({error: response.error}));
return;
}
get_user_statuses(res.posts, response); //Passing response object here
});
});
The issue is that response object passed from express route is not defined in get_user_statuses function. Now I have two question:
Why is response object is not defined?
Is there better approach to achieve this arrangement?
res is not defined because you forgot to pass it in internal call. Change get_user_statuses(JSON.parse(body)); to get_user_statuses(JSON.parse(body), res); and it should work
I solved my problem. I needed to create a function with a callback. In case anyone else is stuck at this kind of issue, this post helped me resolve it:
[How to recurse asynchronously over API callbacks in node.js?
I have a code in controller like below:
BASE.APP.post('/uploadFile/:request/:file', function(req, res, next) {
var url = req.usersession.webipAddress;
var path = 'uploads/' + req.params.file;
var formData = new BASE.FormData();
formData.append('fileNameUnique', req.params.file);
formData.append('file', BASE.FS.createReadStream(path));
// console.log(formData);
formData.submit(url + '/service/uploadFile/', function(err, response) {
// console.log(response.statusCode);
res.send(response.statusCode);
});
});
I want to interrupt file upload if status == "cancel", is that
possible?
If status == "cancel" try this:
req.pause()
res.status = 400;
res.end('Upload cancelled');
I don't know much about the way your code works or your workflow. This is a generic soln that most likely will work. Add more code in the question if you want a more specific soln.
try {
if (status === 'cancel') {
throw new Error("Stopping file upload...");
}
} catch (e) {
res.end("the upload was cancelled because of error: " + e.toString());
}
Save the value returned from formData.submit and use that as a handle to call request.abort on.
E.g.
BASE.APP.post('/uploadFile/:request/:file', function(req, res, next) {
var formData = new BASE.FormData();
// ...
var formSubmitRequest = formData.submit(url + '/service/uploadFile/', function(err, response) {
res.send(response.statusCode);
});
statusChanger.on('status-change', function(status) {
if (status === "cancel" && formSubmitRequest) {
formSubmitRequest.abort();
res.send(524);
}
});
}
From https://github.com/form-data/form-data:
For more advanced request manipulations submit() method returns http.ClientRequest object
From https://nodejs.org/api/http.html#http_request_abort:
request.abort()#
Added in: v0.3.8
Marks the request as aborting. Calling this will cause remaining data in the response to be dropped and the socket to be destroyed.
In node.js, i have function that before any action is checking if everything is ok at the start of request (validating JSON etc). Almost everything is working ok, but I have one problem. I don't now how to pass object reference using next();
To call checking function I'm using.
app.all('/:action', frontendProcessor.checkSession());
At the middle of this code, I'm using next()
frontendProcessor.checkSession = function(){
return function(req, res, next) {
var inputJson = req.body.JSONVAR || false,
action = req.params.action;
// validation
frontendProcessor.validateJSON(inputJson, afterValidation);
function afterValidation(err, inputData){
if(err) {
global.consoleLog(err);
res.send(fail);
}else{
if(action == 'login' ){
console.log(inputData);
next(inputData); //<< here, how to pass inputData thru next
}else{
mUsers.checkSessionId(email, sessionId, process);
};
};
};
function process(response) {
if(!response){
global.consoleLog("Security Error: Bad session Id.");
var response = JSON.stringify(badSession);
res.send(response);
}else{
global.consoleLog('Security: session ok! next');
next(inputData);
};
};
};
};
next() shouldn't ever pass data because it's just designed to call the next request handler, not a specific request handler. Nirk's comment is correct, you should attach your data to the req object and read it from there when needed.
I'm trying to redirect a user based on their url path and also if they do not have a particular cookie set.
How do I get nodejs to "do nothing" and continue? The request just hangs if it's executing the else statement. If I remove the else statement the request just hangs as well.
app.get('/*', function (req, res) {
if( !(typeof req.cookies['isLoggedIn'] !== 'undefined' && req.cookies['isLoggedIn'] === true ) && req.url.substring(0, 7) != '/login/' ) {
res.send(403, "You are not logged in");
}else{
//do nothing
}
return;
});
You need to use the next callback to indicate your middleware doesn't have anything else to do.
app.get('/*', function (req, res, next) {
if( !(req.cookies.isLoggedIn !== void 0 && req.cookies.isLoggedIn === true) && req.url.substring(0, 7) != '/login/' ) {
res.send(403, "You are not logged in");
}else{
next();
}
});
You need to put an output.
for example
res.send(200, "You arelogged");
otherwise, your browser will still be waiting for an output.
what do you mean by "continue?"
I am currently routing every page to my pagesController that cannot be found in previous routes by including this line in routes.js:
this.match('/:page', { controller: 'pages', action: 'show' });
I had the idea to let my PagesController handle serving a 404 if not found:
PagesController.show = function() {
var page = this.param('page');
if(page != undefined){
page = page.replace(".html","");
try {
this.render("./"+page);
} catch(error){ //Failed to look up view -- not working at the moment =(
this.redirect({action : "404"});
};
}
return;
};
But my idea is failing. The error cannot be caught, so the fatal still gets served. Should I append a fn to the render call? With what arguments? How does it work? (/simple questions).
It might look something like this:
PagesController.show = function() {
var self = this;
var page = this.param('page');
if (page !== undefined) {
page = page.replace('.html', '');
this.render("./" + page, function(err, html) {
if (! err)
return self.res.send(html);
self.redirect({ action : '404' });
});
} else {
// this will probably never be called, because `page`
// won't be undefined, but still...
this.redirect({ action : '404' });
}
};