my problem is that my session is undefined as in new layers as even after "if" where the session value was set.
/*******************************************/
/**/ var express = require('express'),
/**/ cookieParser = require('cookie-parser'),
/**/ session = require('express-session'),
/**/ bodyParser = require('body-parser'),
/**/ ejs = require('ejs'),
/**/ mysql = require('mysql'),
/**/ md5 = require('md5');
/*******************************************/
var app = express();
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'samurai'
});
connection.connect(function(error) {
if(error) {
console.log("There is a problem with connection to the database.");
return;
}
console.log("Connected with a database.");
});
app.use(cookieParser());
app.use(session({
secret: 'test session',
resave: false,
saveUninitialized: true
}));
var sess;
Here my session is undefined (first I go to the '/sign' address):
app.get('/', function(req, res) {
sess = req.session;
console.log("sesja = "+sess.login); <--------------- undefined
if(sess.login) {
res.render('indexo');
} else {
res.render('index');
}
});
app.post('/sign', function(req, res, next) {
sess=req.session;
var query = 'SELECT * FROM ?? where ??=? AND ??=?';
var table = ["users", "name", req.body.login, "password", md5(req.body.password)];
query = mysql.format(query, table);
connection.query(query, function(err, rows) {
if(err) {
console.log(err);
return;
} else if(rows.length > 0) {
console.log("You have been sucessfully logged in.");
sess.login = req.body.login;
console.log(sess.login); <------------ works fine
} else {
console.log("The name or password is incorrect.");
}
});
console.log(sess.login); <---------------- here again undefined
res.end();
});
The problem is only in sessions case because if I create other global variable next to "var sess;" (for example var test;) and set for the variable a value in the "if" in '/sign" layer, then the "test" would be visible in the other layers and after that "if".
The final question: Why the session.login is invisible after the "if" and in other layer? How to set it properly? Have you some tips for me with sessions creating?
Thank you guys for your time and help.
Setting global variables from an http request is an evil thing to do and is fraught with problems. First off, your server can have multiple requests in flight at the same time from different users. Using globals from requests like this means that different requests will "stomp" on each others globals and all sorts of chaos and bugs will ensue.
Stop using globals at all for session information. If you need to communicate session info to other functions, then pass it to them as function arguments.
And, secondly you MUST understand how async operations work in node.js to have any chance of programming successfully in node.js. You are making several mistakes with your asynchronous programming and that's one main reason why variables aren't set where you think they should be.
In this code:
app.post('/sign', function(req, res, next) {
sess=req.session;
var query = 'SELECT * FROM ?? where ??=? AND ??=?';
var table = ["users", "name", req.body.login, "password", md5(req.body.password)];
query = mysql.format(query, table);
connection.query(query, function(err, rows) {
if(err) {
console.log(err);
return;
} else if(rows.length > 0) {
console.log("You have been sucessfully logged in.");
sess.login = req.body.login;
console.log(sess.login); <------------ works fine
} else {
console.log("The name or password is incorrect.");
}
});
// this is executed BEFORE the connection.query() callback is called
console.log(sess.login); <---------------- here again undefined
res.end();
});
connection.query() is asynchronous. T'hat means that it calls its callback sometime in the future. Thus your console.log(sess.login); at the end of your request is happening BEFORE the callback has ever been called.
You aren't specific about exactly what you want to happen in all the cases in your query, but here's an outline for how the code could work:
app.post('/sign', function(req, res, next) {
var query = 'SELECT * FROM ?? where ??=? AND ??=?';
var table = ["users", "name", req.body.login, "password", md5(req.body.password)];
query = mysql.format(query, table);
connection.query(query, function(err, rows) {
if(err) {
console.log(err);
res.end("Query error");
} else if(rows.length > 0) {
res.end("Logged in successfully");
} else {
res.end("The name or password is incorrect.");
}
});
});
You may find this general answer on asynchronous responses useful: How do I return the response from an asynchronous call?
Related
I'm using an Oracle database, and every time it updates, the server doesn't understand this update and needs me to drop it for it to update the data.
const express = require('express');
const oracledb = require('oracledb');
const app = express();
var cors = require('cors')
app.use (cors())
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
// Connection details for the Oracle database
const connectionString = 'dbprod';
const user = 'sapiensproducao';
const password = 'fabrica';
// Connect to the database
oracledb.getConnection(
{
connectionString: connectionString,
user: user,
password: password
},
function(err, connection) {
if (err) {
console.error(err.message);
return;
}
console.log('Connection was successful!');
// Execute a SQL query
const query = 'SELECT CODEMP,CODORI,NUMORP,SEQEOQ,DATREA,HORREA,CODPRO,CODDER,QTDRE1,QTDRFG,CODLOT,OBSEOQ from USU_VPROEXT ORDER BY DATREA DESC, HORREA DESC';
connection.execute(query, [], (err, result) => {
if (err) {
console.error(err.message);
return;
}
console.log('Query was successful!');
console.log()
// Render the HTML template and pass the query results as a local variable
app.get('/teste', (req, res) => {
res.json(result.rows)
});
});
}
);
app.listen(3000, () => {
console.log('Server is listening on port 3000');
});
I thought of creating a loop for this SELECT function, but how can I create it?
How can I keep running this select in a loop, to keep the data always updated?
In the structure of your web server, you only ever query the database once and then create an endpoint to serve that data. Instead, create an endpoint which queries the data whenever it's invoked. Which may look more like this:
// define the endpoint
app.get('/teste', (req, res) => {
// within the endpoint, query the database
oracledb.getConnection(
{
connectionString: connectionString,
user: user,
password: password
},
function(err, connection) {
if (err) {
console.error(err.message);
// DON'T DO THIS, return an actual response to the user
return;
}
console.log('Connection was successful!');
const query = 'SELECT CODEMP,CODORI,NUMORP,SEQEOQ,DATREA,HORREA,CODPRO,CODDER,QTDRE1,QTDRFG,CODLOT,OBSEOQ from USU_VPROEXT ORDER BY DATREA DESC, HORREA DESC';
connection.execute(query, [], (err, result) => {
if (err) {
console.error(err.message);
// DON'T DO THIS, return an actual response to the user
return;
}
console.log('Query was successful!');
console.log();
// return the results to the user
res.json(result.rows);
});
});
});
The key difference here is that instead of wrapping the endpoint in the query, you wrap the query in the endpoint. So every time the endpoint is invoked it re-queries the database.
Please also note the comments for your error handling. If you just return; from the function and never return a response to the client, the client will just hang until it times out. Return an actual response, which can include error codes, messages, anything you like. Even just res.json(false); would be better than no response at all.
I am trying to implement a use case where users can request to check his password by providing username.
Issue: Node js back-end app returns result before query is complete. I have checked articles explaining async aspect of javascript. However, I am still unsure if the solutions can be applied when there is a rest call involved in between.
High level flow:
Front-end js calls rest api(node.js application) with username to get password
Node app calls DB to get password
Returned password is displayed on front end
Code:
Front-end:
function getPassword() {//Called by clicking button on ui
var username = 'testuser'; //hardcoding for simplicity
$.ajax({
url: urlWhereNodeJsAppIsHosted,
error: function(password) {
console.log('error' + JSON.stringify(password));
}, success: function(data) {
console.log('success' + JSON.stringify(password)); // Displaying on console for now
}
});
}
Back-end(Node js app):
const express = require('express');
const request = require('request');
const mysql = require('mysql');
const app = express();
var connection = mysql.createConnection({
host: 'localhost',
port: '3306',
user: 'dbuser',
password: 'dbuserpassword',
database: 'dbname'
});
connection.connect(function(err) {
if (err) {console.log(err);}
});
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
next();
});
app.get('/verify', (req, res) => {
var username = req.query.username;
var password = 'noresult';
connection.query(
'SELECT * FROM userpassword where user=?, ${[username]}',
function(err, rows, fields) {
password = extractpasswordfromrows(rows);//iterate and get result
}
);
console.log(connection.threadId); //Value is not undefined
res.send(200, { success: password });
});
const PORT = process.env.PORT || 3001;
app.listen(PORT, () => console.log(`listening on ${PORT}`));
Database:
userpassword(user, password) table with existing data.
I am new to javascript as well as thinking asynchronously. Please help with your inputs. Thanks.
The code sends password outside the success callback without waiting for the query to complete. Try
app.get('/verify', (req, res) => {
var username = req.query.username;
var password = 'noresult';
connection.query(
'SELECT * FROM userpassword where user=?, ${[username]}',
function(err, rows, fields) {
password = extractpasswordfromrows(rows);//iterate and get result
res.send(200, { success: password }); // Ok, have password here
}
);
// Not Ok, don't have password here
console.log(connection.threadId); //Value is not undefined
});
I haven't attempted to put in check code to verify that the err parameter in the call back is not truthy, even if logically seen as impossible.
For general treatment of coding against this error, see "How do I return the result from an asynchronous call".
Processing results outside the callback
To avoid nesting code, callback code can resolve or reject a newly created promise depending on processing results, with result and error handling functions attached to the promise using its then/catch methods.
Alternatively in Express you can supply multiple callbacks (middleware functions) to app.get and use next calls to advance to the next middleware function if and when required. As an example based on the post (compiled but not tested):
app.get('/verify',
(req, res, next) => {
var username = req.query.username;
connection.query(
'SELECT * FROM userpassword where user=?, ${[username]}',
function(err, rows, fields) {
if( err) {
res.status(500).send("no result");
}
else {
res.locals.rows = rows;
next();
}
}
);
},
(req,res) => {
const password = extractpasswordfromrows(res.locals.rows); //iterate and get result
res.send(200, { success: password });
}
);
I'm making a simple webapp with facebook login.
If the facebook login button on my page is clicked,
FB.api(
'/me',
'GET',
{"fields":"id,name,birthday,gender"},
function(response) {
$.post('fb_login', response, "json");
}
);
is called, and a router handles '/fb_login' request; in the router the server checks the id of json object is already in its DB. If not, res.render('signup', ...) should be called.
However it didn't work. I already checked that res.render() was called, but the page 'signup.jade' didn't show up.
Here is my source code of router.
var express = require('express');
var router = express.Router();
var mysql = require('mysql');
var pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: '1012'
});
/* GET home page. */
router.post('/', function(req, res, next) {
var userid = req.body.id;
if (userid) {
pool.getConnection(function(err, connection) {
if (err) {
console.error('DB Connection error!!');
return;
}
console.log('DB Connection Success!!');
connection.query('use vasket');
connection.query('select count(*) result from user where userID=?',
[userid], function(err, result, field) {
var isAlreadyUser = result[0].result;
console.log(isAlreadyUser);
if (isAlreadyUser == 1) {
req.session.userid = userid;
res.redirect('/');
res.end();
console.log('DB FB Login Success!!');
connection.release();
}
else {
connection.release();
console.log('FIRST TIME!');
//This method was called, but the page rendered didn't
res.render('signup', {id: req.body.id, name: req.body.name, birthday: req.body.birthday, gender: req.body.gender});
}
});
});
} else {
res.redirect('/');
res.end();
}
How can I fix it?
To help debugging maybe you can modify your code like that :
// ... your code before
else {
connection.release();
console.log('FIRST TIME!');
console.log(req.body);
//This method was called, but the page rendered didn't
res.render(
'signup',
{
id : req.body.id,
name : req.body.name,
birthday: req.body.birthday,
gender : req.body.gender
} ,
function(err, html){
if(err) console.log(err);
console.log(html);
//res.send(html);
// trying same but forcing status
res.status(200).send(html);
}
);
}
});
});
} else {
res.redirect('/');
res.end();
}
This is an older question, but it's still in need of a solid answer. I had the exact same problem, but I think I've figured it out.
If the server's returning the proper response, that's not where your problem lies. jQuery (in the browser) will render the response, but you have to tell it to do so.
Here's what I had that was responding properly but not rendering:
$("#getsome").click(function() {
$.get("/task/create");
});
And here's how I got it to render:
$("#getsome").click(function() {
$.get("/task/create", function( data ) {
document.write(data);
});
});
Note that you may not need to replace the entire DOM like I'm doing.
References:
Replacing the entire
DOM
jQuery.get
I have a website that is accessing a local node.js server (that accesses a mongolab database), but when I use a front-end function to request a user JSON object, the mongo database returns nothing. (JSON.parse() finds an unexpected end of data at line 1 col 1)
Here is the front-end function that requests the user data by email and password:
function requestUser(email, password) {
xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "http://localhost:8888/getUser/" + email + "/" + password, true);
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
user = JSON.parse(xmlhttp.responseText);
console.log(user);
}
}
xmlhttp.send();
}
Here is the node.js express server (back-end):
var http = require("http"),
mongojs = require("mongojs"),
express = require('express'),
cors = require('cors'),
fs = require("fs"),
url = require("url");
app = express();
app.use(cors());
var uri = "mongodb://<dbuser>:<dbpassword>#ds036698.mongolab.com:36698/alirodatabase";
var db = mongojs(uri, ["Papers", "Users"]);
app.get('/getUser/:email/:passwd', function(req, res, next) {
var users = db.Users.find({"email": req.params.email,
"password": req.params.passwd});
user = users.toArray[0];
res.json(user);
});
app.listen(8888, function() {
console.log('CORS-enabled web server listening on port 8888');
});
EDIT 1:
app.get('/getUser/:email/:passwd', function(req, res, next) {
var user = db.Users.findOne({
"email": req.params.email,
"password": req.params.passwd
}, function(err, doc) {
if (err) {
res.json({error: 'error retrieving the JSON user' });
}
else {
res.json(doc);
}
});
});
I added async functionality to the nodeserver, but now I am receiving the err: "error retrieving the JSON user". Is this a problem that could be solved by hosting my own database and not using mongolab?
You need to look at the docs for mongojs (https://github.com/mafintosh/mongojs). You're not using callbacks at all. The functions don't return values because it's Javascript/Node.js where things like to be async. So you have to use callbacks to handle the results. The idea is "find these documents" and then some time later when it actually gets the documents "do something with the documents".
app.get('/getUser/:email/:passwd', function(req, res, next) {
var users = db.Users.find({
"email": req.params.email,
"password": req.params.passwd
}, function(err, docs) {
if (err) {
//handle the error
res.json({error: ':(' });
}
else {
docs.toArray(function(err, users) {
if (err) {
//handle the error
res.json({error: ':(' });
}
else {
res.json(users[0]);
}
});
}
});
});
Lastly, I'd recommend using findOne rather than find. Then you won't need to use toArray to get a single document because it's returned as a single document in the first callback.
I am trying to inject a session value into the request so i can use it on different situation on my app. What i am doing is calling a function by giving the id to search for a user into database and return me the name of that specific user. The issue i am facing is when i try to declare the session, it looks like is not working or the callback is not letting this new value out.
Let me show you my code example for an better idea:
The middleware
var express = require('express');
var session = require('express-session');
var router = express.Router();
var userSession = require('../../helpers/user/userSession');
router.use(function(req, res, next){
if (req.method == "GET") {
if (!req.user) {
req.session.username = '';
}else{
var sess = userSession.findUser(req.user, function(err, user){
if (user) {
console.log(user); //It contains the value i need
req.session.username = user; // Supposed to inject the user value to the username session variable.
};
console.log(req.session.username); //it works until here, out of this function not anymore.
});
console.log(req.session.username); //the req.session.username is empty now
};
return next();
}else{
return next();
}
});
Check if user exist
var mongoose = require('mongoose');
var User = mongoose.model('database')
module.exports = {
findUser: function(user, callback){
User.findOne({ 'unq_id' : user }, function(err, user){
if (err) {
console.log('Error: ' +err);
return callback(err, false);
};
if (user) {
//console.log(user);
return callback(null, user.user_collection.firstname);
}else{
return callback(err, false);
};
});
}
}
One idea is to give to that sess variable the value of user, but it appears very difficult since is asynchronous call. I am sure some of might have run into this issue.
How can i get around this? any suggestion will be much appreciated.
How about this?
router.use(function(req, res, next){
if (req.method == "GET") {
if (!req.user) {
req.session.username = '';
next();
} else {
userSession.findUser(req.user, function(err, user){
if (user) {
req.session.username = user;
};
next();
});
}
} else {
next();
}
});
That way it won't go to the next middleware until after the username has been retrieved.