I created a simple API on a node server. The server is running on the port 9000. I created an endpoint called getUserDetails and I'm passing a simple object. The problem is I can access the API from the browser by entering the full URL 'http://localhost:9000/getUserDetails'.
But I cannot access the API in another HTML file. To elaborate, I created a simple HTML file to test out this API.
My node server:
const app = express();
app.get('/getUserDetails', (req, res) => {
res.send({
firstname : 'Giri',
secondname: 'Aakula',
dob: '15-09-1997',
age: 22,
qualification : 'Graduate',
status : 'pass'
})
})
app.listen(9000);
My HTML file
<!DOCTYPE html>
<html>
<head>
<title>Test page</title>
<style>
h1{
font-size: 50px;
}
</style>
</head>
<script>
fetch('http://localhost:9000/getUserDetails')
.then(
function(response) {
if (response.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' +
response.status);
return;
}
// Examine the text in the response
response.json().then(function(data) {
console.log(data);
});
}
)
.catch(function(err) {
console.log('Fetch Error :-S', err);
});
</script>
<body>
<h1>This is a test page</h1>
</body>
</html>
I forgot to add cors. By adding this one line fixed my issue.
const express = require('express');
const app = express();
app.get('/getUserDetails', (req, res) => {
//this is the updated line
res.setHeader('Access-Control-Allow-Origin', '*');
res.send({
firstname : 'Giri',
secondname: 'Aakula',
dob: '15-09-1997',
age: 22,
qualification : 'Graduate',
status : 'pass'
})
})
app.listen(9000);
So, finally my MMORTS game built on Sails is going to Kongregate.
Had few obstacles, like connecting websockets, but solved now.
Probably the last obstacle is to keep authenticated session. I was using frameworks everywhere and i have no idea how does the authentication sessions work under the hood.
The main problem is probably the CSRF or CORS. I am using Sails v1.0.
So, i start with HTML, which I upload to kongregate. I'm taking the simplest possible example:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<script src="jquery.js"></script>
<script src='https://cdn1.kongregate.com/javascripts/kongregate_api.js'></script>
<script src="sails.io.js"
autoConnect="false"
environment="production"
headers='{ "x-csrf-token": "" }'
></script>
<script type="text/javascript">
io.sails.url = 'https://my-secret-game.com'; // or where you want
</script>
</head>
<script src="main.js"></script>
</html>
And this is the main.js , which I also upload to kongregate
kongregateAPI.loadAPI(function(){
window.kongregate = kongregateAPI.getAPI();
var username = kongregate.services.getUsername();
var id = kongregate.services.getUserId();
var token = kongregate.services.getGameAuthToken();
$.get("https://my-secret-game.com/csrfToken", function (data, jwres) {
var params = {
username: username,
id: id,
token: token,
_csrf: data._csrf
};
$.post("https://my-secret-game.com/kong", params, function(data, jwr, xhr){
// cant set the cookie - because of chrome. this doesnt work
document.cookie = document.cookie + ';authenticated=true;sails.sid=' + data.id;
$.get("https://my-secret-game.com/csrfToken", function (data, jwres) {
var msg = {
testing_authentication: true,
_csrf: data._csrf
};
$.post("https://my-secret-game.com/test", msg, function(data, status){
// getting the 403 Forbidden, CSRF mismatch. trying to access
// the play/test route, which is protected by sessionAUTH
console.log('data.response', data.response)
});
});
});
});
});
The problem is, that i am getting 403 Forbidden whenever I try to POST my Sails backend with sessionAUTH. I also cant set cookies - probably because of Chrome. What can I do? When i get CSRF token, on the next request my Sails app responds about CSRF mismatch. It becomes wrong.
And this is the controller on my Sails backend server
module.exports = {
kong: function (req, res, next) {
var url = 'https://api.kongregate.com/api/authenticate.json';
var kong_api_key = 'my-secred-api-key';
var params = req.allParams();
var request = require('request');
var req_form = {
"api_key": kong_api_key,
"user_id": params.id,
"game_auth_token": params.token
};
request({
url: url,
method: "POST",
json: true,
body: req_form,
timeout: 5000
}, function (err, response, body){
if(err) { console.log(err, 'ERR43'); return res.ok(); }
else {
if(!response.body.success) {
console.log('unsuccessful login from kongregate')
return res.ok();
}
// trying to use a existing user and authenticate to it
User.find({username: 'admin-user'}).exec(function(err, users) {
var user = users[0];
req.session.authenticated = true;
req.session.user = { id: user.id };
// trying to send session_id, so that i could hold it on kongregates cookies as `sid`
return res.send({ user: user, id: req.session.id });
});
}
});
},
Could somoene please help to fix authentication and CSRF of my app?
In case needs more info about my configs, this is the config/session.js
var prefixes = 'dev';
module.exports.session = {
secret: 'my-secret',
cookie: {
secure: false
},
adapter: 'redis',
host: 'localhost',
port: 6379,
ttl: 3000000,
db: 0,
prefix: prefixes + 'sess:',
};
config/policies.js
module.exports.policies = {
user: {
'new': 'flash',
'create': 'flash',
'edit': 'rightUser',
'update': 'rightUser',
'*': 'sessionAuth'
},
play: {
'*': 'sessionAuth'
}
};
api/policies/sessionAuth.js
module.exports = function(req, res, next) {
if (req.session.authenticated) {
return next();
} else {
var requireLoginErr = [
{ name: 'requireLogin', message: 'You must be signed in' }
];
req.session.flash = {
err: requireLoginErr
};
res.redirect('/');
return;
}
};
config/security.js
module.exports.security = {
csrf: true,
cors: {
allowRequestMethods: 'GET,PUT,POST,OPTIONS,HEAD',
allowRequestHeaders: 'content-type,Access-Token',
allowResponseHeaders: '*',
allRoutes: true,
allowOrigins: '*',
allowCredentials: false,
},
};
Okey, since i had no answers (obviously - the question was bad), answering with my solution which i have solved by my self - so the next time i can read my self. Not sure how good it is, but at least it works.
Sails CORS is taken form Express.js and allows to connect sockets to kongregate if i allow it inside configs.
But it does not allow to authenticate in a normal way, by sending sails.sid (authentication token) via cookies.
Chrome does not allow to set cookies with javascript (i dont have backend on Kongregate) to headers at all due to security. So, if i can't send cookies with headers, Sails can't authenticate the requests in a normal way. Even if i allow CORS to accept the 'cookie' header - it's not allowed by browsers to set cookie headers with javascript.
I can make some unique header like "authentication" and set the sails.sid there, extend some core functionality of Sails to take this new header instead of cookie header. But the problem - on Sails backed i was not able to get at all this sails.sid and send it to my external frontend.. Where it is created? How can i get sails.sid on Sails backend? Not sure - can't google it.
So, i just did authentication in a most simple way possible - on account login/register, i just create a session key by my self - with bcrypt hashing user_id+secret_token (taken from sails config secrets). and sending to the frontend { user_id: 'abcd', secret_token: 'a2dw412515...' }
I have made my policies in Sails to authenticate on every POST/GET request - take the request's session_id and user_id, and compare using bcrypt, does the session_id is the same as encrypted user_id+secret_token. I hope its secure enough.
So, it worked. I just had to disable CSRF. Maybe some day i will implement it again, I just have to write it in my way, not leave the Sails defaults.
The working code:
FRONTEND
// you upload this HTML file to kongregate
// also you upload additionally ZIP named "kongregate_uploaded_folder" with libraries like sails.io, jquery
<!DOCTYPE html>
<html>
<head>
<script src="kongregate_uploaded_folder/jquery.js"></script>
<script src='https://cdn1.kongregate.com/javascripts/kongregate_api.js'></script>
<script src="kongregate_uploaded_folder/sails.io.js"
autoConnect="false"
environment="production"
></script>
</head>
<body style="padding:0; margin:0; overflow:hidden;">
<div style="position:absolute; margin: 0px; padding: 0px;">
<canvas id="main_canvas" style="position:absolute;" width="640" height="480" >Best initial resolution to have in Kongregate</canvas>
</div>
<script>
// the first thing happends - you try to connect your frontend with Kongregate
kongregateAPI.loadAPI(function(){
window.kongregate = kongregateAPI.getAPI();
if(!kongregate.services.isGuest()) {
var params = {
username: kongregate.services.getUsername(),
id: kongregate.services.getUserId(),
token: kongregate.services.getGameAuthToken(),
};
// call your backend to create a new session and give you session_id
$.post("https://your_game_server.com/kong", params, function(data, jwr, xhr){
var kong_session_id = data.kong_session_id;
var kong_user_id = data.kong_user_id;
var user = data.user;
// connect your sockets with the server in this way
io.socket = io.sails.connect("https://your_game_server.com", { useCORSRouteToGetCookie: false, reconnection: true });
// subscribe to the global sockets channel. You have to make this route and code, but here is a example
io.socket.get('/subscribe', { kong_session_id: kong_session_id, kong_user_id: kong_user_id }, function(data, jwr){
if (jwr.statusCode == 200){
io.socket.on(data.room, function(event){
// on any server-side event, you will get this "event" message. At this part you decide what to do with this data
incoming_socket_event(event); // i wont write this function
});
// your game continues here:
$.get("https://your_game_server.com/player_data?kong_session_id=" + kong_session_id + "&kong_user_id=" + kong_user_id, params, function(data, jwr, xhr){
// you will get authenticated "current_user"
}
});
})
}
});
</script>
</html>
BACKEND
// SAILS BACKEND: home_controller.js
module.exports = {
kong: function (req, res, next) {
// player has already opened your game in kongregate.com and frontend requests this endpoint POST /kong { id: 84165456, token: 'as54..' }
// you need to create a new session for this player, or register this player. This is your own session creation, since default sails session wont work with external website frontend.
var req_params = {
url: "https://api.kongregate.com/api/authenticate.json", // default URL to validate kongregate user
method: "POST",
json: true,
body: {
api_key: 'gg000g00-c000-4c00-0000-c00000f2de8', // kongregate will provide this api-key for server-side connection (this one has some letters replaced)
user_id: 84165456, // when frontend requests POST /kong { id=84165456 } , this 84165456 is provided by kongregate in the frontend
game_auth_token: "as54a45asd45fs4aa54sf" // when frontend requests POST /kong { token = 'as54..' }, this is provided by kongregate in the frontend
},
timeout: 20000
}
// request kongregate that this is the real player and you will get a username
request(req_params, function (err, response, body){
var response_params = response.body; // response from kongregate API
// search for user with this kongregate_id inside your database, maybe he is already registered, and you need just to create a new session.
User.find({ kongregate_id: response_params.user_id }).exec(function(err, usr) {
var user = usr[0]
// if player already has an account inside your online game
if(user) {
// create new session for this user.
require('bcryptjs').hash("your_own_random_secret_key" + user.id, 10, function sessionCreated(err, kong_session_id) {
// send this info to frontend, that this player has been connected to kongregate
return res.send({
user: user,
kong_session_id: kong_session_id,
kong_user_id: user.id
});
});
//if this is new user, you need to register him
} else {
var allowedParams = {
username: response_params.username, // kongregate will give you this player username
email: 'you_have_no_email#kong.com', // kongregate does not provide email
password: 'no_password_from_kongregate',
kongregate_id: response_params.user_id // kongregate will give you this player id
};
User.create(allowedParams, function(err, new_user) {
// create new session for this user.
require('bcryptjs').hash("your_own_random_secret_key" + new_user.id, 10, function sessionCreated(err, kong_session_id) {
// send this info to frontend, that this player has been connected to kongregate
return res.send({
user: new_user,
kong_session_id: kong_session_id,
kong_user_id: new_user.id
});
});
});
}
});
});
},
};
ROUTES
// config/routes.js
module.exports.routes = {
'GET /player_data': 'PlayController.player_data',
'GET /subscribe': 'PlayController.subscribe',
'POST /kong': {
action: 'home/kong',
csrf: false // kongregate is a external website and you will get CORS error without this
},
};
SECURITY
// config/security.js
module.exports.security = {
csrf: false,
cors: {
allowOrigins: ['https://game292123.konggames.com'], // your game ID will be another, but in this style
allowRequestMethods: 'GET,POST',
allowRequestHeaders: 'Content-Type',
allowResponseHeaders: '',
allRoutes: true,
allowCredentials: false,
},
};
SOCKETS
// config/sockets.js
module.exports.sockets = {
grant3rdPartyCookie: true,
transports: ["websocket"],
beforeConnect: function(handshake, cb) { return cb(null, true); },
};
CONFIG POLICIES
// /config/policies.js
module.exports.policies = {
play: {'*': 'sessionAuth'},
};
API POLICIES
// /app/sessionAuth.js
module.exports = function(req, res, next) {
var params = req.allParams();
// your own session handling way to get the user from session token
require('bcryptjs').compare("your_own_random_secret_key" + params.kong_user_id, params.kong_session_id, function(err, valid) {
req.session.authenticated = true;
req.session.user_id = params.kong_user_id;
return next();
});
};
CONTROLLER
// /api/controllers/PlayController.js
module.exports = {
player_data: async function (req, res, next) {
var users = await User.find(req.session.user_id);
return res.send({ current_user: users[0] });
},
subscribe: async function (req, res, next) {
var users = await User.find(req.session.user_id);
var roomName = String(users[0].id);
sails.sockets.join(req.socket, roomName);
res.json({ room: roomName });
},
}
Could you please tell me how to download server file in node js
here is my code
Node js code (request code)
var express = require('express');
var multer = require('multer');
var bodyParser = require('body-parser');
var cors = require('cors');
var app = express();
var path = require('path');
var PORT = process.env.PORT || 3000;
// use of body parser
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.use(cors());
app.get('/download', function(req, res){
console.log(__dirname);
var file = path.join(__dirname , '/uploads/file-1534458777206.xlsx');
console.log(file)
res.download(file); // Set disposition and send it.
});
app.listen(PORT, () => {
console.log(`App is listening to ${PORT}`);
})
I am requesting like that on client
$('.download').on('click', function () {
$.ajax({
url: 'http://localhost:3000/download',
type: 'GET',
dataType: 'json',
success: function (data) {
console.log('data')
},
error: function (jqXHR, textStatus, errorThrown) {
// Handle errors here
console.log('ERRORS: ' + textStatus);
// STOP LOADING SPINNER
}
});
getting error on console
ERRORS: parsererror
3index.html?_ijt=9lu9erpan2oq6qf28851ngj0ra:32 ERRORS: parsererror
2index.html?_ijt=9lu9erpan2oq6qf28851ngj0ra:32 ERRORS: parsererror
server logs
C:\Users\B0207296\WebstormProjects\uploadFile\server
C:\Users\B0207296\WebstormProjects\uploadFile\server\uploads\file-1534458777206.xlsx
why files is not download on client as I mention file is present in above url
To get the file content via ajax:
Just remove the dataType, your file is being parsed to json causing the error.
$('.download').on('click', function () {
$.ajax({
url: 'http://localhost:3000/download',
type: 'GET',
success: function (data) {
console.log(data); // File data
},
error: function (jqXHR, textStatus, errorThrown) {
// Handle errors here
console.log('ERRORS: ' + textStatus);
// STOP LOADING SPINNER
}
});
To download the file is better user a virtual link
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<b class="download">Download Here</b>
<script>
$('.download').on('click', function () {
var link = document.createElement('a');
link.href = 'http://localhost:3000/download';
var e = document.createEvent('MouseEvents');
e.initEvent('click', true, true);
link.dispatchEvent(e);
})
</script>
</body>
</html>
I have html file called temp.html
I want to display select query result in that html page.
This is my select query.
SELECT cs_name FROM course_master where cs_id = 4
This query will return following result.
[ { cs_name: 'JAVA programming' } ]
I want to display this result in html page.
Basically I want to use the "GET" request and response using node js.
This is my node js file structure.
var mysql = require('mysql');
var connection = mysql.createConnection({
host : '127.0.0.1',
user : 'root',
password : '',
database : 'eduportal'
});
connection.connect();
connection.query('SELECT cs_name FROM course_master where cs_id = 4', function(err, rows, fields) {
if (!err)
console.log('The solution is: ', rows);
else
console.log('Error while performing Query.');
});
connection.end();
This is my HTML file.
<!doctype html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title></title>
</head>
<body>
<div id="course_name">
Course Name:<input type="text" id="cname">
</div>
</body>
</html>
I want to display course name in text box which I defined in HTML file.
Can anyone help to bind this text box with mysql using node js?
You can achieve this by socket.io. You need to learn more about this to understand following snippet.
In this i have provided a sample code to full fill your requirement.
Might be possible that some tweaks still in this code so you can change those by your understanding.
Let me clarify about following server.js snippet
In this you can put your all queries to get or set in db.
//server.js
var app = require("express")();
var mysql = require("mysql");
var http = require('http').Server(app);
var io = require("socket.io")(http);
/* Creating POOL MySQL connection.*/
var pool = mysql.createConnection({
host : '127.0.0.1',
user : 'root',
password : '',
database : 'eduportal'
});
app.get("/", function(req, res) {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', function(socket) {
console.log("A user is connected");
get_cs_name(function(res,cs_name) {
if (res) {
io.emit('get_cs_name', cs_name);
} else {
io.emit('error');
}
});
});
var get_cs_name = function(callback) {
pool.getConnection(function(err, connection) {
if (err) {
connection.release();
callback(false);
return;
}
connection.query("SELECT cs_name FROM course_master where cs_id = 4", function(err, rows) {
connection.release();
if (!err) {
callback(true,rows[0].cs_name);
}
});
connection.on('error', function(err) {
callback(false,null);
});
});
}
http.listen(3000, function() {
console.log("Listening on 3000");
});
Now run "node server.js" command from CLI. Your http request will be handle on 3000 port. please keep this in mind.
//index.html
<html>
<head>
<title>Socket.io</title>
<script src="/socket.io/socket.io.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<script src = "http://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<script>
$(document).ready(function(){
var socket = io();
socket.on('get_cs_name',function(cs_name){
alert(cs_name);
$("#cname").val(cs_name);
});
});
</script>
</head>
<body>
<div id="course_name">
Course Name:<input type="text" id="cname">
</div>
</body>
</html>
Now its time to browse your html file to see your actual result that it is working or not, please hit http://localhost:3000 in browser.
If any error found please ping me back here.
Thanks
I am learning Node.Js, I would like to understand how to interact between front-end / backend.
I would do backend --> Front End interaction by sendig data using app.get(), but now, I'd like to understand how can I get variable from Front End to Backend.
Front-ENd. (I want to pass varGetFromFrontend to backend)
<html>
<script>
var varGetFromFrontend = 2; // This is variable I want to pass to backend
</script>
<head>
<title>Home Page</title>
</head>
<body>
<h1> This is a test</h1>
</body>
</html>
On Node.Js (backend)
var express = require('express');
var app = new express();
app.use(express.json());
app.use(express.static(__dirname + '/public'));
var entries = [
{"id":1, "title":"Hello World!"},
{"id":2, "title":"Hello World!"}
{"id":3, "title":"Hello World!"}
{"id":4, "title":"Hello World!"}
];
if(entries.id == varGetFromFrontend){
console.log("This is to print a variable by choosing it from Front End")
console.log(varGetFromFrontend)
}
var port = Number(process.env.PORT || 5000);
app.listen(port);
I would like to know how can I print "varGetFromFrontend" on server side
Make an HTTP request to the server. Include the variable in the request.
There are lots of ways to do this:
Put it in a hidden input in a form, then submit the form.
or
Set location.href to a new value and include the variable in it (e.g. in a query string)
or
Use the XMLHttpRequest object to make an HTTP request
or
Create a script element and include the variable in the URL for the src attribute
(This is a non-exhaustive list)
You can interact with the nodejs server from the browser with socket.io
First, install socket.io:
npm install socket.io
and write these code to their respective filenames.
app.js:
var express = require("express");
var http = require("http");
var socketIO = require("socket.io");
var app = express();
app.get("/", function(req, res){
res.sendfile("./index.html");
});
var server = http.createServer(app);
var io = socketIO.listen(server, {log: false});
io.sockets.on("connection", function(socket){
socket.on("sendVar", function(value){
console.log("The value of the variable is " + value);
});
});
server.listen(5000);
index.html:
<html>
<head>
<title>Index Page</title>
</head>
<script type="text/javascript" src="/socket.io/socket.io.js"></script>
<script type="text/javascript">
var variableFromFrontEnd = 2;
var socket = io.connect("/");
socket.on("connect", function(){
console.log("connected!")
socket.emit("sendVar", variableFromFrontEnd);
});
</script>
</html>
and run it.
Check out the MEAN framework I built: http://mean.wolframcreative.com/
This uses Node as the back-end server utilizing Express as the API router. The front-end uses angular and is purely an api consumption tool.
Short answer is this:
in angular:
$http
.get('/api/users/bobsaget')
.success(function (response) {
console.log(response);
});
in node(with express):
app.get('/api/users/:username', function (req, res) {
var variable = req.params.username;
//do logic here with the database(mongo) to get user info:
db.users.findOne({username: username}, function (error, response) {
if (!error) {
res.send(200, response);
} else {
res.send(500, {success: false, message: error.message});
}
});
)};
Long answer is to play around with my framework and get your hands dirty.
I'm currently working on a restful framework for node call snooze. I'm writing an api along side it and it's going very well. The framework is written to be modular and easy to use. Everything is built around modules, routes, controllers, services, and validators.
https://github.com/iamchairs/snooze
snooze.module('myServer', ['snooze-stdlib']) // inject the snooze-stdlib module
.route('get', '/users/:username', { // define the route
controller: 'UserCtrl', // what controller should handle this route
action: 'getUserByUsername', // what action to perform on this route
validator: 'GetUsername' // before processing this action what validation should occur
})
.controller('UserCtrl', function(User) { // inject the User service
return {
getUserByUsername: function(res, options) {
User.getUserByUsername(options.query.username).then(function(username) {
res.send(200, username);
}).fail(function(err) {
res.send(500, err);
});
}
};
})
.service('User', function($q) { // inject the $q service
return {
getUserByUsername: function() {
var deferred = $q.defer();
deferred.resolve('iamchairs');
return deferred.promise;
}
};
})
.validator('GetUsername', function($validator) { // inject the validator service
return function(deferred, req) {
if($validator.isLength(req.query.username, 2, 32)) {
deferred.resolve(); // resolve (valid request)
} else {
deferred.reject([400, 'Username must be between 2 and 32 characters']); // reject (invalid request)
}
}
});