Send data to server using socket.io with Node.js - json

in simple form i use:
onsubmit="return sendMessage()" action="/register"
to send data with socket.io to server:
function sendMessage() {
var name = document.getElementById("Name").value;
socket.emit('new_rgs', {
'name': name,
});
return false;
}
and i want to save result to text file too,
i use express.js to do this:
app.post('/register', urlencodedParser, (req, res) => {
var info = {};
info["name"] = req.body.Name;
fs.appendFileSync("register.json", JSON.stringify(info));
res.render('pages/register', {
"send": 1
});
});
but post method doesn't send anything :(
if you want check all codes it's here

You need to do a separate call to the /register route. What your current code does is that it only does an emit to the socket. You need a separate AJAX call towards the register route.

Related

I'm not using Express, but I'm trying extract POST data then to send a json as response, with no luck

I'm still very new to node.js so please bear with me.
I'm trying to extract POST data then sent a json as response, but I don't seem to be able to extract the data from the POST request and even worse I can't find the syntax for people who are NOT using Express to send the json. It keeps telling me res.json is not a function.
EDIT: I found out the problem for the json part, I was a dump. I finally remember what I was told, json are sent like strings.
var http = require('http');
var qs = require("querystring");
server = http.createServer(function (req, res) {
try {
var body = "";
var post = qs.parse("");
if (req.method == "POST") {
res.writeHeader(200, {"Content-Type": "application/json"});
req.on("data", function (data) {
body += data;
console.log(data); //It gives something like <Buffer xx xx xx ...>
if (body.length > 1e6)
req.connection.destroy();
});
req.on("end", function () {
post = qs.parse(body);
console.log(post.test); //It gives "undefined"
});
res.end(JSON.stringify({ a: 1 }));
} catch(err) {
console.dir(err);
res.writeHeader(200, {"Content-Type": "text/plain"});
res.end("Hi hi");
}
});
server.listen(8000);
console.log("http start #8000");
Any help? Thanks in advance.
below solves the date to string (i.e. converting buffer to string
res.on('data', function(chunk) {
var textChunk = chunk.toString('utf8');
// console.log(textChunk); // will give you a stream of text from data
});
you could store textChunk out of the ondata handler, to then use that if required (say returning relevant data to the user back again)

Express Multiple res.json(); with middlewares

I'm trying to build a stateless API using JWT. I have a middleware function in my Router which checks if the JWT has expired, if it has, a new Token with a new timestamp is generated on the fly.
I would like to pass the new token along with the response in the JSON Object. My current approach is like this, but it of course doesn't work:
router.use(function (req, res, next) {
// JWT Expired
// Generate new JWT
res.write(JSON.stringify({token: token});
next();
});
router.get('/securedRoute' function(req, res) {
// Fetch data
res.json({data: data});
});
:
// Output should be:
{token: 'erg34jlkgjre.3f4fknlj.34f3', data: ['sdfa', 'sdf']}
It would be nice to find a way, where I don't have to alter all of my existing code and check if there is a new token.
Thanks for your help!
One option would be to add the authorization token in the response header:
router.use((request, response, next) => {
response.setHeader('Token', token);
next();
});
router.get('/securedRoute', (request, response) => {
response.json({ data: data });
});
Alternatively, you could always add the token to the request and then conditionally add the request.token into all of your routes like the previous answer suggested. Unfortunately that would mean that you need to modify all of your routes.
As an alternative you could override the response.json method and manually inject the token if it exists. In doing so, you wouldn't need to modify any of your routes.
router.use((request, response, next) => {
request.token = token;
((proxied) => {
response.json = function (data) {
if (request && request.token) {
data.token = request.token;
}
return proxied.call(this, data);
};
})(response.json);
next();
});
router.get('/securedRoute', (request, response) => {
response.json({ data: data });
});
In the example above, the response.json method is overridden in the middleware. This is done by passing a reference to the old response.json method and then calling it after conditionally injecting the token into the payload.
The answer is assuming you want to achieve that in same method
Rather than writing the token in middleware do something like
(req,res,next)=>{
req.token = newToken;
next();
}
And in your route
res.json(req.token ? {token:req.token,data:data} : {data:data});

passport send error by json

I'm making an app with express + passport and angularJS; I want to be able to send any errors produced from passport (such as username taken or no email provided) by json so my angularJS app can receive these errors in a json response. More specifically right now I want to have a json response to my signup POST method that outputs any errors. I have tried to do this for myself and I've search all over the web and stack overflow I just cannot work this out!
Here is my users route file in express:
var express = require('express');
var router = express.Router();
var isAuthenticated = require('../config/isAuthenticated');
module.exports = function(passport){
router.get('/loggedin', function(req, res){
res.send(req.isAuthenticated() ? req.user : '0');
});
router.post('/signup', passport.authenticate('local-signup', {
successRedirect : '/',
failureRedirect : '/signup',
failureFlash: true
}));
router.post('/login', passport.authenticate('local-login'), function(req, res){
res.send(req.user);
});
router.post('/signout', function(req,res){
req.logout();
res.json({redirect: '/'});
});
router.get('/authtest', isAuthenticated, function(req, res){
res.render('authtest', {user: req.user});
});
return router;
};
This is my passport signup strategy:
passport.use('local-signup', new LocalStrategy({
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true
},
function(req, username, password, done){
process.nextTick(function(){
User.findOne({'local.username' : username}, function(err, user){
if(err) return done(err);
if (user) { //username already exists
return done(null, false, {message: 'Username already exists'});
} else if(!req.body.email) { //no email address provided
return done(null, false, {message: 'You must provide an email address!'});
} else {
var newUser = new User();
newUser.local.username = username;
newUser.generateHash(password, function(err, hash){
if(err) return done(err);
newUser.local.password = hash;
});
newUser.email = req.body.email;
newUser.servers = [];
newUser.save(function(err){
if(err) throw err;
return done(null, newUser);
});
};
});
});
}
));
I know looking at my code right now it looks like I haven't tried to solve this myself at all but this is just my latest working code; I have been stuck at this for the past few days!
Any help would be greatly appreciated :)
According to the current code of passport this is probably achievable by passing custom callback to handle all results of authentiction yourself. This callback is given after options or instead of those.
passport( "local-signup", { ... }, callbackFn );
or
passport( "local-login", callbackFn );
This callback is used in all resulting situations of trying to authenticae. It is thus invoked on processing errors like this:
callbackFn( err )
If (all configured) authentications have failed it is called with
callbackFn( null, false, challenge(s), status(es) )
On successfully having authenticated user the callback is invoked like so:
callbackFn( null, user, infos )
with infos optionally provided by strategies.
Now comes the bottom-side: In either situation passport.authenticate() skips usual processing but instantly invokes provided callback to care for the rest. This includes processing of any options passed in call for passport.authenticate() like flashing messages, preparing session and request for containing authenticated user etc.
Since options given passport.authenticate() are never passed into callback there is actually no obvious reason to use both.
When I was stumbling over the very same problem (linking passport-service with angular-js POST request) I declined to consider use of callback a proper solution. This callback isn't documented. And it doesn't even look quite useful for it isn't passing req, res and next to pass any actual request in callback. Thus it makes very little sense to use it at all and I'd expect it to vanish soon or to change its behaviour quite much.
So the second approach was about trying to figure out why there is a problem in AngularJS. Passport is sending plain text Unauthorized in response with status code 401. AngularJS is trying to parse this as JSON and produces Syntax error. The text Unauthorized results from passprt ending response very simply by invoking
res.statusCode = 401;
res.end(http.STATUS_CODES[res.statusCode]);
Thus a proper workaround might try to replace
either text in http.STATUS_CODES though this is having impact on processing further requests and thus isn't preferrable
or res.end() by an overloaded method acting differently if res.statusCode is 401.
Due to affecting any current request, only, I tried the latter. Replaced res.end() might be used to send any text you want:
router.post('/login',
function(req, res, next) {
var _end = res.end;
res.end = function() {
if (res.statusCode === 401) {
return _end('{"status":"Unauthorized"}');
}
return _end.apply(this, arguments);
};
next();
},
passport.authenticate('local-login'),
function(req, res) {
res.send(req.user);
}
);
Alternatively the replaced method might add previously missing response header information on content type, for this was actually causing issues in AngularJS processing that response as JSON by default.
router.post('/login',
function(req, res, next) {
var _end = res.end;
res.end = function() {
if (res.statusCode === 401) {
res.set("Content-Type", "text/plain");
}
return _end.apply(this, arguments);
};
next();
},
passport.authenticate('local-login'),
function(req, res) {
res.send(req.user);
}
);
Finally, either approach is really just a workaround. I think passport is in the need for revising this annoying limitation.

How emit event name can be dynamic in Node.js?

I am trying to create dynamic EventEmitter in Node.js. So , how can the event name can be dynamic.
Code :
var express = require('express'),
app = express(),
server = require('http').createServer(app),
io = require('socket.io').listen(server);
num = "1";
fs = require('fs');
server.listen(4000);
function handler(req,res){
fs.readFile(__dirname + '/index.html',
function(err,data){
res.writeHead(500);
res.end(data);
});
}
app.get('/', function(req, res){
res.sendfile(__dirname + '/index.html');
});
io.sockets.on('connection', function(socket){
socket.on('send message'+num, function(data){
io.sockets.emit('new message'+num, data);
});
});
right now in this example i have given value "1" but i want it to dynamic , so how can i get the dynamic value from a html file. So , that emit event name can be dynamic.
Please let me know , suggest me some solution.
There is rarely a valid reason to use a dynamically created message name and it seriously complicates the life of whoever is trying to listen for those messages (they may not know what message name to listen for). Use one message name and then put the number in the data structure that goes with the message.
sending:
io.sockets.emit('new-message', {data: data, item: num});
receiving:
socket.on('new-message', function(msgData){
if (msgData.item === xx) {
// handle just a particular message number here
}
}

Server sent event: Client not receiving response from server

I'm trying to use server sent events so my webpage can have periodic time updates from my server. The issue is that my client is able to interact with my server, however, the response from my server is not making it to my client? Basically, when I open my html file with firefox I know my server gets the request and then it starts sending responses, but nothing shows up on my webpage... Not quite sure what's the issue. Help appreciated!
Here is my client code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<script>
function init(){
if(typeof(EventSource)!=="undefined"){
var source = new EventSource('localhost');
source.onmessage = function(e) {
document.body.innerHTML += e.data + '<br>';
};
}
else{
document.body.innerHTML = "Sorry, your browser does not support server-sent events...";
}
}
</script>
<body onload="init()">
</body>
</html>
Here is my server code (node.js):
var http = require('http');
var sys = require('sys');
var fs = require('fs');
http.createServer(function(req, res) {
if (req.headers.accept && req.headers.accept == 'text/event-stream') {
sendSSE(req, res);
}).listen(80, "127.0.0.1");
function sendSSE(req, res) {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
var id = (new Date()).toLocaleTimeString();
// Sends a SSE every 5 seconds on a single connection.
setInterval(function() {
constructSSE(res, id, (new Date()).toLocaleTimeString());
}, 5000);
}
function constructSSE(res, id, data) {
res.write('id: ' + id + '\n');
res.write("data: " + data + '\n\n');
}
You need to add in
res.end();
somewhere and remove the 'setInterval'. It looks like what you're trying to do, however, is keep the connection alive, in which case you need to change your code significantly. Look into the 'net' module, which is more designed for a "constant on" interactive type of connection.
http://nodejs.org/api/net.html#net_net
The http module is designed for finite, exchange of data, type of requests. You're trying to make it do something it isn't designed to do.
/*jshint node:true */
var http = require('http');
http.createServer(function (req, res) {
'use strict';
console.log('GOOD request recieved');
res.write('hi there');
res.end();
console.log('GOOD end sent');
}).listen(8888);
http.createServer(function (req, res) {
'use strict';
console.log('BAD request received');
res.write('hi there');
console.log('BAD response wrote not ending');
}).listen(8889);
Consider the two servers I have above. If you ping them both with node client code, you will see data come in to both, and should see chunks as they are sent. However, if you try to ping 8889 with a browser, the webpage will never render, because the end event is never sent. Browsers depend on this to know all content has been received. If you're client code is working within a browswer, this may be effecting things. Attempt to use plain NodeJS client code against your server first, and make sure data is getting sent the way you expect it is. Then work on figuring out how the browser is upsetting things. My guess would be that the data gets received by the browser, but it never does anything with it, and sits and waits to distribute it for that 'end' event, the same way in which the 8889 server's webpage never renders... it believes there is more data to wait for.
Sample client code:
var options = {
hostname: '127.0.0.1',
method: 'GET'
};
options.port = 8888;
http.request(options, function (res) {
'use strict';
console.log('GOOD Pinged server');
res.on('data', function (chunk) {
console.log('GOOD data chunk:' + chunk);
});
res.on('end', function () {
console.log('GOOD end event recieved');
});
}).end();
options.port = 8889;
http.request(options, function (res) {
'use strict';
console.log('BAD Pinged server');
res.on('data', function (chunk) {
console.log('BAD data chunk:' + chunk);
});
res.on('end', function () {
console.log('BAD end event recieved');
});
}).end();
The http module in node works fine for Server Sent Events and most demo code for Node SSE uses it. But you do have to be careful about some gotchas.
I got bit by compression being turned on. The solution there is to add res.flush() after the last res.write() of each data message. Since that's an easy fix, I would try that first before rewriting using a different module.