I am making a request to the facebook api to get a list of friends. When I make the request through node.js, my request is always truncated. Does anyone understand why the response is being truncated?
Here is the code of my function:
var loadFriends;
loadFriends = function(access_token, callback) {
var https, options, start;
https = require('https');
start = new Date();
options = {
host: 'graph.facebook.com',
port: 443,
path: '/me/friends?access_token=' + access_token
};
return https.get(options, function(res) {
console.log("Request took:", new Date() - start, "ms");
res.setEncoding("utf8");
return res.on("data", function(responseData) {
var data;
console.log(responseData);
data = JSON.parse(responseData);
return callback(data);
});
});
};
The res.on('data') event will happen multiple times as chunks of data arrives; you need to concatenate this together to get the whole response.
http://nodejs.org/docs/v0.4.0/api/http.html#event_data_
Related
I'm adding a contact me section to a website. I want to be able to send the data from the forms with JS, and then receive and do something with the data with Node. I understand that there are frameworks and libraries that can handle this stuff, but I would like to build it from scratch so that I have a better understanding of what is happening.
I currently have a section of JS (see below) that is taking the form data, and sending it as a POST request to the node script, but I can't seem to wrap my head around what is happening with node, or how to receive the data with the node script. Any help in pointing me in the right direction is greatly appreciated.
const name = $(".name");
const email = $(".email");
const message = $(".message");
const submitButton = $(".submitButton");
const nameRegex = /([a-zA-Z\s-])/g;
const emailRegex = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/g;
const messageRegex = /([a-zA-Z\s.,?!$%&])/gm;
const url = "../node/contactMeSubmissionHandler.js"
submitButton.click(function(){
let nameContents = name.val().match(nameRegex).join("");
let emailContents = email.val().match(emailRegex).join("");
let messageContents = message.val().match(messageRegex).join("");
// if (emailRegex.test(emailContents) == true) {
// let emailValid = emailContents;
// } else {
// console.log("Email is invalid");
// };
const data = {
email: emailContents,
name: nameContents,
message: messageContents
}
$.post(url, data, function(data, status){
console.log(`${data} and status is ${status}`);
})
})
I like to write from scratch too. Here is working code which is called from a command line to get a token.
// clientEx.js
var http = require('http');
var fs = require('fs');
const _SERVER = "dcsmail.net"; /* dcsmail.net */
// Callback function is used to deal with response
//
var callback = function (response)
{
// update stream with data
var body = '';
response.on('data', function(data) {
body += data;
});
response.on ('end', function()
{
// Data received completely.
fs.writeFileSync ("temp.lst", body, 'utf8');
// console.log ("clientEx.js received: " + body);
});
}
if ((process.argv[2] == null) || (process.argv[3] == null) || (process.argv[4] == null) || (process.argv[5] == null))
{
console.log ("clientEx.js usage:<user email> <user password> <destination> <GUID>");
}
else
{
var Ef_email = encodeURI (process.argv[2]);
var Ef_pass = encodeURI (process.argv[3]);
var Ef_dest = encodeURI (process.argv[4]);
var Ef_guid = encodeURI (process.argv[5]);
var post_data = ("f_email=" + Ef_email +
"\&" + "f_pass=" + Ef_pass +
"\&" + "f_dest=" + Ef_dest +
"\&" + "f_guid=" + Ef_guid);
// Options to be used by request
var options = {
host: _SERVER,
port: '80',
path: '/DCSM/tokenP10.php',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength (post_data)
}
};
// console.log ("clientEx.js using " + _SERVER + ":" + options.port + options.path);
// request the token from the host
try
{
var req = http.request (options, callback);
req.write (post_data);
req.end();
}
catch (error)
{
fs.writeFileSync ("temp.lst", "Host access failed\n", 'utf8');
}
}
You should be able to adapt that to your needs.
Use this code to create a server and check the log in console for different request attributes.
const http = require('http');
http
.createServer((request, response) => {
console.log(request);
response.end();
})
.listen(3000);
Make GET and POST request to http://localhost:3000/ and look for method, headers etc.
See more here and here.
I have a data coming to NodeJS and then it needs to be served to Ajax query. but because the NodeJS is transfering it as chunked data, none of the general Javascript/JQuery ajax methods are able to capture the packet.
How can i get the values
nodeJS:
http.createServer(options, (req, res) => {
msg = c++_to_javascript();
res.writeHead(200);
res.end(msg);
}).listen(89);
Javascript/JQuery:
received the data as transfer encoded: chunked as a result no methods are able to decode the received packets in JS.
How could i solve it from NodeJS or in JS?
TRY 1: FAILED
$.stream(javascript_to_c++,{
open:function(){
console.log("opened");
},
message:function(event){
console.log(event.data);
buf1 = buf1 + event.data;
},
error:function(){
console.log("error");
},
close:function(){
console.log("closed");
}
});
TRY2 : FAILED
var test = $.ajax({
type: "GET",
url: javascript_to_c++,
async: false,
success:function(m) {
buf1 = buf1 + m;
}
}).responseText;
console.log(test);
TRY 3: FAILED
// Define a method to parse the partial response chunk by chunk
var last_index = 0;
function parse(xhr) {
var curr_index = xhr.responseText.length;
if (last_index == curr_index) return; // No new data
var s = xhr.responseText.substring(last_index, curr_index);
last_index = curr_index;
console.log(s);
}
function test() {
var xhr = new XMLHttpRequest();
var url = javascript_to_c++;
xhr.open("GET", url, true);
xhr.send();
// Check for new content every 5 seconds
var interval = setInterval(parse, 5000);
// Abort after 25 seconds
setTimeout(function(){
clearInterval(interval);
parse(xhr);
xhr.abort();
}, 25000);
}
test();
You just have to properly wait for the response to come back. I'm not too familiar with the other ajax methods you're using but let's look at this for example:
var test = $.ajax({
type: "GET",
url: javascript_to_c++,
async: false,
success:function(m) {
buf1 = buf1 + m;
}
}).responseText;
console.log(test);
Are you expecting test to be the response? $.ajax returns a Promise representing the asynchronous request. It's not until the success callback is called or the promise is resolved when you'll get the response text. Try this instead:
var test = $.ajax({
type: "GET",
url: javascript_to_c++, // I'm assuming this is a valid URL?
success:function(content) {
console.log(content); // This is your actual full response.
}
});
As far as having the node process specify the content type, try the content-type header:
res.set('content-type', 'text/plain');
res.end(msg);
Update:
As already pointed out, it's highly doubtful that the Transfer-Encoding thing is actually a problem. It you do want to disable it, do:
res.set('transfer-encoding', '');
...but really, it shouldn't be necessary.
Another Update:
Not using Express? You'll just need to slightly modify this:
res.writeHead(200, {
'content-type': 'text/plain',
'transfer-encoding': '' // not recommended...
});
res.end(msg);
When trying to load simple JSON APIs with the following code, I noticed the speeds were extremely slow:
function get(url, callback) {
http.get(url, function(r) {
var body = "";
r.on('data', function(d) {
body+=d;
});
r.on('end', function() {
callback(body, false)
});
}).on('error', function (err) {
callback(null, err.message.code)
});
}
Or posting with the following code:
function post(url, post_data, callback) {
if (!post_data) post_data = "";
var Proto = url.split("://")[0]+":";
var Host = url.split("://")[1].split("/")[0];
var Path = "/"+url.split("://")[1].replace("/", "#CHECK").split("#CHECK")[1];
var req = http.request({
host: Host,
port: '80',
path: Path,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(post_data)
}
}, function(r) {
var body = '';
r.on('data', function(d) {
body += d;
});
r.on('end', function() {
callback(body);
});
}).on('error', function (err) {
callback(null, err.message.code)
});
req.write(querystring.stringify(post_data));
req.end();
}
Both take an extremely long time to go through, usually averaging me about 150-300 milliseconds per request on small files that would take me under 80ms to load in Google Chrome. To test, I used Google Chrome to benchmark and sent simple get and post requests, but it took 2 to 3 times longer to receive a response in node for each request than it did in Google Chrome. After doing some research, I found out it could possibly be due to Chrome, like most browsers, using the Connection:"keep-alive" header, but adding this in the headers seemed to have no impact. I'm already setting http.globalAgent.maxSockets = 100000; so I know that isn't the issue. How I can speed up my requests?
Still have yet to find anything, if anyone knows if anything to speed things up please post a reply
Traditionally I use jQuery for all my JS code, but I'm tasked to launch a simple API with node.js. Today is my first day with Node but I know enough about JS and closures to do OK. One of the tasks of the API is to authenticate across a third party service and being a python guy, I wanted to abstract all my outbound request calls like so:
EDIT
var http = require('http');
var init = function(nconf) {
var methods = {
/*
Helper method to create the request header
*/
headers: function(params) {
var content = JSON.stringify(params);
return {
'Content-Type': 'application/json',
'Content-Length': content.length
}
},
/*
Helper method to create the options object
which is used in making any type of
outbound http request
*/
options: function(host, path, method, params) {
return {
host: host,
port: 80,
path: path,
method: method,
headers: methods.headers(params)
}
},
/*
Helper method to abstract the making of
outbound http requests
*/
call: function(options, params, success, err) {
var req = http.request(options, success);
req.on('error', err);
req.write(params);
req.end();
},
/*
Helper method to parse the response
and return a json object
*/
parse: function(res, result) {
var responseString = '';
res.on('data', function(data) {
responseString += data;
});
res.on('end', function() {
result = JSON.parse(responseString);
});
},
/*
API method to return the latest
release and tag names
*/
latest: function(req, res, next){
// // var url = nconf.get('prod:authenticate');
//authenticate the test user
msg = methods.authenticate(nconf.get('test:user'), nconf.get("test:password"));
res.send(msg);
next();
},
/*
Method used by this API to authenticate users.
It is used to de-couple this API from the Database
Schema by calling out to the TTCPAS App and requesting it
to handle the authentication
*/
authenticate: function(username, password){
// create post parameters with API key
var params = {"username": username, "password": password, "api_key": nconf.get('api_key')};
//construct options object with params and header
var options = methods.options(nconf.get('ttcpas:host'), nconf.get('ttcpas:auth_url'), 'POST', params);
var result;
var success = function(res) {
res.setEncoding('utf-8');
methods.parse(res, result);
};
methods.call(options, params, success, function(err){});
while (typeof(result.statusCode) == 'undefined') {
//wait 1 second;
setTimeout(function(){
console.log("waiting on request at " + nconf.get('ttcpas:host') + nconf.get('ttcpas:auth_url'));
}, 1000);
}
//then down here
if (result.statusCode == 200) {return result};//success
if (result.statusCode == 403) {return "forbidden"};//forbidden
}
}
return methods;
};
module.exports.init = init;
#jfriend00 As I said I don't know how node.js is supposed to be styled. I wanted to just abstract as much as possible to make the code clean and reusable
Now when I do http://localhost:9000/latest/
I get:
{"code":"InternalError","message":"first argument must be a string or Buffer"}
Uhhh, this part will simply not work:
while (typeof(result.statusCode) == 'undefined') {
//wait 1 second;
setTimeout(function(){
console.log("waiting on request at " + nconf.get('ttcpas:host') + nconf.get('ttcpas:auth_url'));
}, 1000);
}
If result.statusCode is ever undefined, this will spin forever piling up setTimeout() calls in the event queue until eventually something fills up or you run out of memory.
Because node.js is primarily single threaded, you can't loop waiting for something to change. Because you never finish this while loop, no other node.js code gets to run so result.statusCode can never change. Thus, you have an infinite loop here.
All of your nodejs code needs to be event driven, not spin/wait loops. FYI, this is similar to browser-based Javascript.
I have a text input field on my webpage, userID in which the user specifies a bit of information that will be appended to a JSON request. The function fetchJSON is called when the user submits their info.
The code is as follows:
function fetchJSON(){
//get user input
var userID = document.getElementById("userID").value;
//create request and options
var https= require("https");
var options = {
host: "api.example.com",
path: "/GetHistory/V001/account_id=" + userID,
method: "GET"
};
//handle request
var request = https.request(options, function(response){
var body = "";
response.on("data", function(chunk){
body += chunk.toString("utf8");
});
response.on("end", function(){
var json = JSON.parse(body);
console.log(json);
});
});
request.end();
}
The code works when I run it from terminal with the userID hardcoded (node main.js) but I am in the dark as to how I can run it from a webpage with user defined input.
Thanks for any help!
First of all, node.js can't manipulate the client-side DOM.
So you need to pass the variable to server, so using express as mentioned in the comments after you have generated a basic website
setup a basic get route
app.get('/api/getprofilebyid/:id',function(req,res){
//get user input
var userID = req.params.id; //document.getElementById("userID").value;
//create request and options
var https= require("https");
var options = {
host: "api.example.com",
path: "/GetHistory/V001/account_id=" + userID,
method: "GET"
};
//handle request
var request = https.request(options, function(response){
var body = "";
response.on("data", function(chunk){
body += chunk.toString("utf8");
});
response.on('error',function(err){
res.json(500,{'error':err}); // an error occured.
});
response.on("end", function(){
request.end(); // and the request.
res.json(200,body); // output json
});
});
});
and request using ajax or simply browse to url..
using jQuery ajax $.get on client-side
var userID = document.getElementById("userID").value;
$.get('/api/getprofilebyid/'+userID,function(response){
// handle response
});