Getting JSON-objects with Node.js WITHOUT stream - javascript

I am trying to make a JSON-objects exchange between client (web-browser) and server (Node.js) with vanilla javascript. I use a httpRequest in client and POST method. On server, I want to get a JSON-data from that POST-request, but I feel like that streams and chunks are too complicated. Is there a way to get data like a simple object? Does it exist at all?
Client-side request (looks OK):
button.onclick = function serverCommunication() {
var serverInteraction = new XMLHttpRequest('POST', '/chooochooo', true);
serverInteraction.open("POST", '/logInAttempt', true);
serverInteraction.setRequestHeader('Content-Type', 'application/json');
serverInteraction.send(JSON.stringify(myObject));// JSON-data has been sent, hoooraaaa!
};

You can try this
if(req.method === 'POST')
let body = '';
req.on('data', chunk => {
body += chunk.toString();
});
console.log(body);
But this has its limitations and i would suggest using express for handling requests.

Related

how to: wsse soap request in javascript (node)

I need to communicate with a soap:xml API from a node server on the Wix.com platform. The API requires Soap WSSE authentication.
I can send an authenticated request to the endpoint in SoapUI, however haven't been able successfully do this on the Wix node platform.
Wix only have a subset of node packages available for install and XMLHttpRequest is not available in their environment.
I have tried node-soap but receive errors which indicate the package might be buggy on the Wix node platform.
I've found myself using the node "request" (https://www.npmjs.com/package/request) package and trying to roll my own solution to work around missing node packages and environment restrictions.
Currently I can send a request to the end point however I receive the following response;
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Client</faultcode><faultstring>Access denied</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>\n
This suggests to me i'm not authenticating correctly.
As I mentioned, I've been able to successfully send requests and receive expected responses via SoapUI. So the API is functioning, and I suspect it's my implementation that is at fault. I'll be honest, I've worked with REST/JSON API's in the past, and it has been a long time since i've worked with a SOAP API, and I remember even back then having a whole lot of pain!
my request code
import request from 'request';
import {wsseHeaderAssoc} from 'backend/wsse';
export function getLocationID() {
let apiUsername = "username";
let apiPassword = "password";
let apiURL = "https://api.serviceprovider.com/wsdl";
// WSSE authentication header vars
    let wsse = wsseHeaderAssoc(apiUsername, apiPassword);
let wsseUsername = wsse["Username"];
let wssePasswordDigest = wsse["PasswordDigest"];
let wsseCreated = wsse["Created"];
let wsseNonce = wsse["Nonce"];
let xml =
`<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:masked:api">`+
`<soapenv:Header>`+
`<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">`+
`<wsse:UsernameToken wsu:Id="UsernameToken-19834957983507345987345987345">`+
`<wsse:Username>${wsseUsername}</wsse:Username>`+
`<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">${wssePasswordDigest}</wsse:Password>`+
`<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">${wsseNonce}</wsse:Nonce>`+
`<wsu:Created>${wsseCreated}</wsu:Created>`+
`</wsse:UsernameToken>`+
`</wsse:Security>`+
`</soapenv:Header>`+
`<soapenv:Body>`+
...
`</soapenv:Body>`+
`</soapenv:Envelope>`
var options = {
url: apiURL,
method: 'POST',
body: xml,
headers: {
'Content-Type':'text/xml;charset=utf-8',
'Accept-Encoding': 'gzip,deflate',
'Content-Length':xml.length,
'SOAPAction':"https://api.serviceprovider.com/wsdl/service",
'User-Agent':"Apache-HttpClient/4.1.1 (java 1.5)",
'Connection':"Keep-Alive"
}
};
let callback = (error, response, body) => {
if (!error && response.statusCode == 200) {
console.log('Raw result ', response);
// If you ever get this working, do some mad magic here
};
console.log('Error ', response);
};
}
I'm using wsse-js (https://github.com/vrruiz/wsse-js/blob/master/wsse.js) to generate the PasswordDigest, Created datetime stamp and Nonce as the node wsse package (https://www.npmjs.com/package/wsse) isn't available on Wix. I've read over the code and based on what i've read elsewhere this looks like a good implementation.
I made one small addition to return the generated details in an assoc array;
export function wsseHeaderAssoc(Username, Password) {
var w = wsse(Password);
var wsseAssoc = [];
wsseAssoc["Username"] = Username;
wsseAssoc["PasswordDigest"] = w[2];
wsseAssoc["Created"] = w[1];
wsseAssoc["Nonce"] = w[0];
return wsseAssoc;
}
As stated earlier i'm receiving a response of;
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Client</faultcode><faultstring>Access denied</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>\n
And i'm expecting a valid SOAP XML response.
I've used the raw xml structure and headers from SoapUI to construct this, everything looks fine, i really have no idea where i'm going wrong.
I would love any pointers anyone could throw my way - I've lost 2 days trying to brute force this, I need help.
You can use the WSSecurity method from the soap package. An example from their README:
var options = {
hasNonce: true,
actor: 'actor'
};
var wsSecurity = new soap.WSSecurity('username', 'password', options)
client.setSecurity(wsSecurity);

How to connect node.js app with python script?

I've node app in Meteor.js and short python script using Pafy.
import pafy
url = "https://www.youtube.com/watch?v=AVQpGI6Tq0o"
video = pafy.new(url)
allstreams = video.allstreams
for s in allstreams:
print(s.mediatype, s.extension, s.quality, s.get_filesize(), s.url)
What's the most effective way of connecting them so python script get url from node.js app and return back output to node.js? Would it be better to code it all in Python instead of Meteor.js?
Well, there are plenty of ways to do this, it depends on your requirements.
Some options could be:
Just use stdin/stdout and a child process. In this case, you just need to get your Python script to read the URL from stdin, and output the result to stdout, then execute the script from Node, maybe using child_process.spawn. This is I think the simplest way.
Run the Python part as a server, let's say HTTP, though it could be anything as long as you can send a request and get a response. When you need the data from Node, you just send an HTTP request to your Python server which will return you the data you need in the response.
In both cases, you should return the data in a format that can be parsed easily, otherwise you are going to have to write extra (and useless) logic just to get the data back. Using JSON for such things is quite common and very easy.
For example, to have your program reading stdin and writing JSON to stdout, you could change your script in the following way (input() is for Python 3, use raw_input() if you are using Python 2)
import pafy
import json
url = input()
video = pafy.new(url)
data = []
allstreams = video.allstreams
for s in allstreams:
data.append({
'mediatype': s.mediatype,
'extension': s.extension,
'quality': s.quality,
'filesize': s.get_filesize(),
'url': s.url
})
result = json.dumps(data)
print(result)
Here is a very short example in NodeJS using the Python script
var spawn = require('child_process').spawn;
var child = spawn('python', ['my_script.py']);
child.stdout.on('data', function (data) {
var parsedData = JSON.parse(data.toString());
console.log(parsedData);
});
child.on('close', function (code) {
if (code !== 0) {
console.log('an error has occurred');
}
});
child.stdin.write('https://www.youtube.com/watch?v=AVQpGI6Tq0o');
child.stdin.end();

any way to send a function with socket.io?

guys.
I want to send a function to browser with socket.io, but failed to do it.
On server side, I response a function with emit, but I get a undefined on browser.
Is there any way to get a function from server with socketio?
there is my code.
// server.js
var static = require('node-static');
var http = require('http');
var file = new(static.Server)();
var app = http.createServer(function(req, res) {
file.serve(req, res);
}).listen(8000);
io = require('socket.io').listen(app);
io.sockets.on('connection', function(socket) {
socket.on('schedule', function() {
console.log('SCHEDULE TASK');
socket.emit('schedule', function() { console.log('hello world'); });
});
});
// client.js
var socket = io.connect('http://localhost:8000');
socket.on('schedule', function(fn) {
fn();
});
socket.emit('schedule');
You cannot send an actual function. You could send a string of Javascript and then you could turn that into a function in the client.
But, I'd suggest you really ought to rethink what you're trying to do here. Generally, the client already has the code it needs (from the script tags that it downloaded) and you send the client data which it then passes to the code it already has or data that it uses to make decisions about which code that it already has to call.
If you show us the real world problem you're trying to solve, we can likely suggest a much better solution than sending a string of Javascript code to the client.
If you really wanted to send a function, you would have to turn it into a string first, send the string, then use the string to turn it back into a function in the client by using a Function object or eval() or creating your own dynamic script tag with inline source.
You can only send strings via socket.io, not functions. That being said, I suggest you to send function names instead.
//server.js
socket.emit('schedule', 'helloworld');
//client.js
function helloworld(){
console.log('hello world');
}
socket.on('schedule',function(name){
window[name](); //hello world
});

Node JS HTTP GET request body

I am using the express module in node.js and I am trying to read the body of an HTTP GET request and send an answer back to the user based on the content of the body. I am new to node.js and this is not working for me.
I know I should be using HTTP POST for this (and it works when I am using post), but the server I am trying to mimic in node.js uses GET, so I have to stick to it. Is there a way to do this in node.js? Thanks!
Here is a sample code I did. When I use app.post, I see the logs for the body, but when I use app.get, I see no logs at all!
app.get('/someURL/', function(req, res){
var postData = '';
req.on('data', function(chunk) {
console.log("chunk request:");
console.log(chunk);
postData += chunk;
});
req.on('end', function() {
console.log("body request:");
console.log(postData);
});
//Manipulate response based on postData information
var bodyResponse = "some data based on request body"
res.setHeader('Content-Type', 'application/json;charset=utf-8');
res.setHeader('Content-Length', bodyResponse.length);
res.send(bodyResponse);
};
The version of Node's HTML parser you are using does not support bodies in GET requests. This feature is available on the latest unstable v0.11 branch.
https://github.com/joyent/node/issues/7575
https://github.com/joyent/node/issues/5767

Basic Ajax send/receive with node.js

So I'm trying to make a very basic node.js server that with take in a request for a string, randomly select one from an array and return the selected string. Unfortunately I'm running into a few problems.
Here's the front end:
function newGame()
{
guessCnt=0;
guess="";
server();
displayHash();
displayGuessStr();
displayGuessCnt();
}
function server()
{
xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET","server.js", true);
xmlhttp.send();
string=xmlhttp.responseText;
}
This should send the request to server.js:
var http = require('http');
var choices=["hello world", "goodbye world"];
console.log("server initialized");
http.createServer(function(request, response)
{
console.log("request recieved");
var string = choices[Math.floor(Math.random()*choices.length)];
console.log("string '" + string + "' chosen");
response.on(string);
console.log("string sent");
}).listen(8001);
So clearly there are several things going wrong here:
I get the feeling the way I am "connecting" these two files isn't correct both in the xmlhttp.open method and in using response.on to send the string back to the front end.
I'm a little confused with how I call this page on localhost. The front end is named index.html and the sever posts to 8001. What address should I be go to on localhost in order to access the initial html page after I have initialized server.js? Should I change it to .listen(index.html) or something like that?
are there other obvious problems with how I am implementing this (using .responsetext etc.)
(sorry for the long multi-question post but the various tutorials and the node.js source all assume that the user already has an understanding of these things.)
Your request should be to the server, NOT the server.js file which instantiates it. So, the request should look something like this: xmlhttp.open("GET","http://localhost:8001/", true); Also, you are trying to serve the front-end (index.html) AND serve AJAX requests at the same URI. To accomplish this, you are going to have to introduce logic to your server.js that will differentiate between your AJAX requests and a normal http access request. To do this, you'll want to either introduce GET/POST data (i.e. call http://localhost:8001/?getstring=true) or use a different path for your AJAX requests (i.e. call http://localhost:8001/getstring). On the server end then, you'll need to examine the request object to determine what to write on the response. For the latter option, you need to use the 'url' module to parse the request.
You are correctly calling listen() but incorrectly writing the response. First of all, if you wish to serve index.html when navigating to http://localhost:8001/, you need to write the contents of the file to the response using response.write() or response.end(). First, you need to include fs=require('fs') to get access to the filesystem. Then, you need to actually serve the file.
XMLHttpRequest needs a callback function specified if you use it asynchronously (third parameter = true, as you have done) AND want to do something with the response. The way you have it now, string will be undefined (or perhaps null), because that line will execute before the AJAX request is complete (i.e. the responseText is still empty). If you use it synchronously (third parameter = false), you can write inline code as you have done. This is not recommended as it locks the browser during the request. Asynchronous operation is usually used with the onreadystatechange function, which can handle the response once it is complete. You need to learn the basics of XMLHttpRequest. Start here.
Here is a simple implementation that incorporates all of the above:
server.js:
var http = require('http'),
fs = require('fs'),
url = require('url'),
choices = ["hello world", "goodbye world"];
http.createServer(function(request, response){
var path = url.parse(request.url).pathname;
if(path=="/getstring"){
console.log("request recieved");
var string = choices[Math.floor(Math.random()*choices.length)];
console.log("string '" + string + "' chosen");
response.writeHead(200, {"Content-Type": "text/plain"});
response.end(string);
console.log("string sent");
}else{
fs.readFile('./index.html', function(err, file) {
if(err) {
// write an error response or nothing here
return;
}
response.writeHead(200, { 'Content-Type': 'text/html' });
response.end(file, "utf-8");
});
}
}).listen(8001);
console.log("server initialized");
frontend (part of index.html):
function newGame()
{
guessCnt=0;
guess="";
server();
displayHash();
displayGuessStr();
displayGuessCnt();
}
function server()
{
xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET","http://localhost:8001/getstring", true);
xmlhttp.onreadystatechange=function(){
if (xmlhttp.readyState==4 && xmlhttp.status==200){
string=xmlhttp.responseText;
}
}
xmlhttp.send();
}
You will need to be comfortable with AJAX. Use the mozilla learning center to learn about XMLHttpRequest. After you can use the basic XHR object, you will most likely want to use a good AJAX library instead of manually writing cross-browser AJAX requests (for example, in IE you'll need to use an ActiveXObject instead of XHR). The AJAX in jQuery is excellent, but if you don't need everything else jQuery offers, find a good AJAX library here: http://microjs.com/. You will also need to get comfy with the node.js docs, found here. Search http://google.com for some good node.js server and static file server tutorials. http://nodetuts.com is a good place to start.
UPDATE: I have changed response.sendHeader() to the new response.writeHead() in the code above !!!
Express makes this kind of stuff really intuitive. The syntax looks like below :
var app = require('express').createServer();
app.get("/string", function(req, res) {
var strings = ["rad", "bla", "ska"]
var n = Math.floor(Math.random() * strings.length)
res.send(strings[n])
})
app.listen(8001)
https://expressjs.com
If you're using jQuery on the client side you can do something like this:
$.get("/string", function(string) {
alert(string)
})
I was facing following error with code (nodejs 0.10.13), provided by ampersand:
origin is not allowed by access-control-allow-origin
Issue was resolved changing
response.writeHead(200, {"Content-Type": "text/plain"});
to
response.writeHead(200, {
'Content-Type': 'text/html',
'Access-Control-Allow-Origin' : '*'});
Here is a fully functional example of what you are trying to accomplish. I created the example inside of hyperdev rather than jsFiddle so that you could see the server-side and client-side code.
View Code:
https://hyperdev.com/#!/project/destiny-authorization
View Working Application: https://destiny-authorization.hyperdev.space/
This code creates a handler for a get request that returns a random string:
app.get("/string", function(req, res) {
var strings = ["string1", "string2", "string3"]
var n = Math.floor(Math.random() * strings.length)
res.send(strings[n])
});
This jQuery code then makes the ajax request and receives the random string from the server.
$.get("/string", function(string) {
$('#txtString').val(string);
});
Note that this example is based on code from Jamund Ferguson's answer so if you find this useful be sure to upvote him as well. I just thought this example would help you to see how everything fits together.

Categories

Resources