MIddleware run twice - javascript

I created a Middleware to get rid of my page request but it seems to run twice...
The first time it run has no error and second time has errors...
This is my code:
app.js file
app.get('/:slug', buildingController.findBuilding, buildingController.getBuilding);
buildings.js file
/**
* Create a Middleware to Find Buildings
*/
exports.findBuilding = function(req, res, next) {
if (!req.isAuthenticated()) {
return res.redirect('/login');
}
Building.find(
{ "uniqueLink": req.params.slug,
"$or": [
{ "_creator": req.user.id }
]
}, function(err, building) {
if (err) {
return next(err);
} else {
if (building.length == 0 || building == null) {
req.flash('errors', { msg: 'You are not allowed to see this building' });
res.redirect('/buildings');
next();
} else {
req.building = building[0];
next();
}
}
}
);
};
/**
* GET /:slug
* Building home page.
*/
exports.getBuilding = function(req, res) {
var building = req.building;
res.render('building/home', {
title: building.name,
building: building
});
};
This is the console output:
Express server listening on port 3000 in development mode
GET /my-slug 200 359.399 ms - -
Good, no errors but then:
TypeError: Cannot read property 'name' of undefined
[...etc...]
Where I'm failing?
On my page everything works fine but I wish to no have errors...
I'm still learning Node.js.
Thanks.

if (building.length == 0 || building == null) {
I think next() shouldn't be called in this case

Related

Node js works fine but how do I get it on browser?

I have a table in sql Server and I am trying to display it in web browser and apply datatable(jQuery) to it. Below code works fine as it gives the output in command line. But I'd have to get it on the browser(probably in json format).
I am using 'tedious' for connection as that's what I found in Express.js documentation.
var express = require('express');
var app = express();
var Connection = require('tedious').Connection;
var Request = require('tedious').Request;
var config = {
userName: 'clientinfo',
password: 'clientinfo123',
server: 'USW20051234'
}
var connection = new Connection(config);
connection.on('connect', function (err) {
if (err) {
console.log(err);
} else {
executeStatement();
}
});
function executeStatement() {
request = new Request("SELECT * from dbo.Logs", function (err, rowCount) {
if (err) {
console.log(err);
} else {
console.log(rowCount+' rows');
}
connection.close();
});
request.on('row', function (columns) {
columns.forEach(function (column) {
if (column.value === null) {
console.log('NULL');
} else {
console.log(JSON.stringify(column.value));
}
});
});
connection.execSql(request);
}
You need to start HTTP server. As you already define APP try this
app.get('/urltest', (req, res) => {
res.send('hello from nodejs');
});
const PORT = 5000;
app.listen(PORT);
console.log('Listening on :' + PORT + '...');
and try http:localhost:5000/urltest on a browser
Thank You everyone for all the suggestions. I think "tedious" was giving me a hard time so I did npm install mssql and that worked like a charm.
Below is the link I referred to.
http://www.tutorialsteacher.com/nodejs/access-sql-server-in-nodejs

TypeError: Cannot read property 'regenerate' of undefined

I'm new to node.js and trying to use 'express-session' to create and storage a session, the title is the bug, and below is my code. I check the origin code on github, but didn't find any question. pls help, thank you so much.
User.prototype.login = function (req, res, next) {
pool.getConnection(function (err, connection) {
// 获取前台页面传过来的参数
var user_name = req.param("user_name"),
password = req.param('password');
// 建立连接,向表中插入值
var select = mysql.format(user_command.login, user_name);
connection.query(select, function(err, result) {
if(result) {
if(result[0].password === password){
req.session.regenerate(function() {
if(err){
res.json({ret_code: 2, ret_message:'登陆失败' });
}
res.sessionID = user_name;
res.json({ret_code: 0, ret_msg: '登录成功'});
});
}else {
res.redirect('/login');
}
}
// 释放连接
connection.release();
});
});
};
Express middleware are executed in the order that you define them. Your problem is that you have set app.use('./', routes) before app.use(session(...)).
To fix this, just move the first line after the second.
app.use(session({
// ...
});
app.use('./', routes);

Redirect if session is not available node.js

I am trying to write code for my route that if the session.user_id is undefined redirect back to the home page. For some reason the redirect doesnt execute and the mysql condition is fired and it crashes the server because the session.user_id is undefined and it cant load the game without that data.
Is there a way to use a universal redirect on all routes that if session is not available redirect back to login?
router.get('/game', function(req,res) {
console.log(req.session.user_id);
if (req.session.user_id === "undefined") {
res.redirect('/');
}else {
var condition = 'userId = ' + req.session.user_id;
projectX.allGameData(condition, function(data){
var hbsObject = {heroes : data, logged_in: req.session.logged_in, isUser: req.session.isUser, isAdmin: req.session.isAdmin}
res.render('game', hbsObject);
});
};
});
You should either use:
if (req.session.user_id === undefined)
OR
if ( typeof req.session.user_id === "undefined")
Apart from that, it's usually better to have a middleware function that checks for user session. This way, you can just insert the call to this middleware in all your routes, which require the user to be logged in:
router.get('/game', checkUserSession, function(req,res) {
// Your code here
});
function checkUserSession( req, res, next )
{
if( req.session.user_id )
{
next();
}
else
{
res.redirect('/homepage');
}
}//checkUserSession()
I assume the value is undefined, and not "undefined" (which is a string containing the word "undefined"):
if (req.session.user_id === undefined) {
...
}
//Inject authHandler as middleware
router.get('/my/route/', authHandler, (req, res) => {
//secure point, the authHandle went thru
});
function authHandler(req, res, next) {
if (req.session.user_id) {
next();
}
res.redirect('/login/');
}
Add a function to handle the Auth check and then inject is a middleware to your router.

How to have express handle and capture my errors

var database = require('database');
var express = require('express');
var app = express();
var cors = require('cors');
app.use(cors());
var bodyParser = require('body-parser');
var urlencodedParser = bodyParser.urlencoded({
extended: false
});
app.post('/dosomething', urlencodedParser, function(req, res) {
if (!req.body.a) {
res.status(500).send(JSON.stringify({
error: 'a not defined'
}));
return;
}
firstAsyncFunction(req.body.a, function(err, result) {
if (err) {
res.status(500).send('firstAsyncFunction was NOT a success!');
} else {
if (result.b) {
secondAsyncFunction(result.b, function(err, data) {
if (err) {
res.status(500).send('secondAsyncFunction was NOT a success!');
return;
}
res.send('EVERYTHING WAS A SUCCESS! ' + data);
});
}
else {
res.status(500).send('result.b is not defined');
}
}
});
});
function firstAsyncFunction(param, callback) {
//Some network call:
// Return either return (callback(null,'success')); or return (callback('error'));
var query = database.createQuery(someOptionsHere);
database.runDatabaseQuery(query, function(err, entities, info) {
if (err) {
return (callback('error'));
}
return (callback(null, 'success'));
});
};
function secondAsyncFunction(param, callback) {
//Some network call:
// Return either return (callback(null,'success')); or return (callback('error'));
var query = database.createQuery(someOptionsHere);
database.runDatabaseQuery(query, function(err, entities, info) {
if (err) {
return (callback('error'));
}
return (callback(null, 'success'));
});
};
var server = app.listen(process.env.PORT || 3000, function() {
var host = server.address().address;
var port = server.address().port;
console.log('App listening at http://%s:%s', host, port);
});
module.exports = app;
I have here a basic express http server. This server has one route, dosomething, which makes two network calls and tells the user if they were a success or not.
This is my entire webserver (this is a bare bones server of my actual server for example purposes). I am now concerned with this server crashing. Reading the docs for express I see there is a default error handler which will catch errors and prevent the server from crashing (http://expressjs.com/en/guide/error-handling.html). I have added the code:
function defaultErrorHandler(err, req, res, next) {
if (res.headersSent) {
return next(err);
}
res.status(500);
res.render('error', { error: err });
}
app.use(defaultErrorHandler);
This still crashes my server though. For example. I had a problem with my database returning an improper JSON response and inside of my firstAsyncFunction (not shown in the code) I tried to parse the JSON and it caused an error telling me it was improper JSON and the server crashed and was unable to take requests anymore until I restarted it. I would like to avoid this and have the default error handler send out a generic response back to the user when this occurs. I thought if I specified the defaultErrorHandler and put it inside of app.use that it would capture and handle all errors, but this does not seem to be the case? Inside of my async function for example you can see I am looking if an error was returned and if it was I send an error back to the user, but what if some other error occurs, how can I get express to capture and handle this error for me?
The defaultErrorHandler cannot handle exceptions that are thrown inside asynchronous tasks, such as callbacks.
If you define a route like:
app.get('/a', function(req, res) {
throw new Error('Test');
});
An error will be thrown, and in this case defaultErrorHandler will successfully catch it.
If the same exception occurs in an async manner, like so:
app.get('/a', function(req, res) {
setTimeout(function () {
throw new Error('Test');
}, 1000);
});
The server will crush, because the callback is actually in another context, and exceptions thrown by it will now be caught by the original catcher. This is a very difficult issue to deal with when it comes to callback.
There is more than one solution though. A possible solution will be to wrap every function that is prone to throw error with a try catch statement. This is a bit excessive though.
For example:
app.get('/a', function(req, res) {
setTimeout(function () {
try {
var x = JSON.parse('{');
}
catch (err) {
res.send(err.message);
}
}, 1000);
});
A nicer solution:
A nicer solution, would be to use promises instead, if it's possible, then for example you can declare a single errorHandler function like so:
function errorHandler(error, res) {
res.send(error.message);
}
Then, let's say you have to following function with fetches stuff from the database (I used setTimeout to simulate async behavior):
function getStuffFromDb() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("{");
}, 100);
});
}
Notice that this function returns an invalid JSON string. Your route will look something like:
app.get('/a', function(req, res) {
getStuffFromDb()
.then(handleStuffFromDb)
.catch(function (error) { errorHandler(error, res) });
});
function handleStuffFromDb(str) {
return JSON.parse(str);
}
This is a very simplified example, but you can add a lot more functionality to it, and (at least theoretically) have a single catch statement which will prevent your server from crushing.

Restify static webserver stops working after enabling HTTP basic authentication

I have a working node.js restify server configured to work as a static webserver. Here is the relevant code;
var server = restify.createServer({
name: 'myapp',
version: '1.0.0'
});
var static_webserver = function (app) {
app.get(/.*/, restify.serveStatic({
'directory': 'static', //static html files stored in ../static folder
'default': 'index.html'
}));
} //var static_server = function (app)
static_webserver(server);
After I enable HTTP Basic authentication to have better security for the other REST APIs, the static webserver stopped working.
This is the code for enabling HTTP Basic authentication.
server.use(restify.authorizationParser());
function verifyAuthorizedUser(req, res, next)
{
var users;
users = {
foo: {
id: 1,
password: 'bar'
}
};
if (req.username == 'anonymous' || !users[req.username] || req.authorization.basic.password !== users[req.username].password) {
// Respond with { code: 'NotAuthorized', message: '' }
next(new restify.NotAuthorizedError());
} else {
next();
}
next();
}//function verifyAuthorizedUser(req, res, next)
server.use(verifyAuthorizedUser);
It seems that after enabling authentication, no web browser was able to visit the static html webpages because authentication is required. How can I disable authentication for the static webserver but enable authentication for the other REST APIs?
If your nodejs is up to date enough to support string.startsWith():
function verifyAuthorizedUser(req, res, next) {
var path = req.path();
// check if the path starts with /static/
if (path.startsWith('/static/')) {
return next();
}
var users;
users = {
foo: {
id: 1,
password: 'bar'
}
};
if (req.username == 'anonymous' || !users[req.username] || req.authorization.basic.password !== users[req.username].password) {
// Respond with { code: 'NotAuthorized', message: '' }
next(new restify.NotAuthorizedError());
} else {
next();
}
next();
}
If you don't have startsWith(), a good old regex will do:
if (path.match(/\/static\/.*/)) {
return next();
}

Categories

Resources